用CoreOS和fleet部署hubot的经历

总结

    • CoreOS上にfleetのunitとしてhubotを立ち上げてみた

 

    複数ホスト間でのLINKとかなければfleetは単純なツールなので使いやすかったという話

前提- 这个词用来指代一种前提条件或者先决条件,它是指在探讨或实施某事物之前需要满足的一种基础或者限制。

    • Vagrantとvagrant-digitaloceanがインストール済み

 

    手元にDocker開発環境が整備済み

做过的事情

1. 启动CoreOS

本次我们将通过Vagrant,在DigitalOcean上创建一个CoreOS的droplet。
Vagrantfile的内容如下所示。
请根据需要进行相应的路径和文件名修改后使用。

Vagrant.configure('2') do |config|
  config.ssh.username = 'core'

  config.vm.define "core-hubot" do |config|
    config.vm.provider :digital_ocean do |provider, override|
      override.ssh.private_key_path = '/path/to/your/ssh_key'
      override.vm.box               = 'digital_ocean'
      override.vm.box_url           = "https://github.com/smdahlen/vagrant-digitalocean/raw/master/box/digital_ocean.box"
      provider.token                = "YOUR digitalocean API TOKEN"
      provider.image                = 'coreos-stable'
      provider.region               = 'sgp1'
      provider.size                 = '512MB'
      provider.ssh_key_name         = "YOUR SSH KEY NAME"
      provider.setup                = false
      provider.private_networking   = true
      provider.user_data            = File.read('user-data.yml')
    end
  end
end

此外,本次在启动CoreOS时,我们将以下的user-data.yml文件设置给CoreOS。

#cloud-config

coreos:
  etcd:
    # curl -w "\n" https://discovery.etcd.io/new
    discovery: https://discovery.etcd.io/YOUR_DISCOVERY_PATH
    addr: $private_ipv4:4001
    peer-addr: $private_ipv4:7001

  fleet:
    public-ip: $private_ipv4

  units:
    - name: etcd.service
      command: start
    - name: fleet.service
      command: start

请使用curl -w “\n” https://discovery.etcd.io/new来获取etcd主机发现API。然而,由于本次是单一主机,所以没有特定的用途。但在运营CoreOS集群时是非常重要的。

创建hubot的Docker镜像

这次我们使用单个主机进行运营,所以我们选择将Hubot和Redis作为独立的容器运营,并采用链接运营的形式。Hubot的开发本身是在Docker外的本地环境进行的,在docker构建时将其文件添加进去。开发时的目录结构如下所示。

.
├── Dockerfile    # hubot用Dockerfile
├── Vagrantfile
├── redis.service # redis用serviceファイル
├── hubot         # hubotの関連ファイル群
│   ├── Procfile
│   ├── README.md
│   ├── bin
│   ├── external-scripts.json
│   ├── hubot-scripts.json
│   ├── node_modules
│   ├── package.json
│   ├── scripts
│   └── start.sh
├── hubot-bot.service # hubot用serviceファイル
└── user-data.yml

对于Hubot自身的开发说明,我们将省略不提,但您可以通过查看以下链接来了解更多细节:
https://github.com/github/hubot/blob/master/docs/README.md

我认为使用Dockerfile以node.js作为容器基础,可以轻松地安装hubot。顺便提一下,这次是为了Slack投稿而设置的hubot,所以添加了相关配置。

FROM node:latest
MAINTAINER my@email.address

RUN npm install -g hubot coffee-script hubot-slack
RUN mkdir -p /root/hubot
ADD hubot/package.json /root/hubot/package.json
ADD hubot/bin /root/hubot/bin
RUN cd /root/hubot && npm install
ADD hubot/hubot-scripts.json /root/hubot/hubot-scripts.json
ADD hubot/external-scripts.json /root/hubot/external-scripts.json
ADD hubot/scripts /root/hubot/scripts
ADD hubot/start.sh /root/hubot/start.sh
RUN chmod a+x /root/hubot/start.sh

ENV HUBOT_SLACK_TOKEN YOUR_SLACK_TOKEN

CMD ["/root/hubot/start.sh"]

关于Hubot的启动,您只需查看最后一个CMD,就可以知道我们是通过执行简单的Shell脚本来进行的。

#! /bin/sh
export REDIS_URL="redis://$REDIS_PORT_6379_TCP_ADDR:$REDIS_PORT_6379_TCP_PORT"
cd /root/hubot/
bin/hubot -a slack

在这里,我们假设已经使用名称为redis的link将Redis的URL构建起来。

将此Dockerfile构建并推送到Docker Hub的私有注册表中,即可完成Docker Hubot镜像的准备工作。

创建用于hubot和Redis的服务文件

Fleet会使用类似于systemd配置文件的配置文件,在集群内启动指定的服务单元。

這是Redis的啟動。

[Unit]
Description=Redis
After=docker.service
Requires=docker.service

[Service]
TimeoutStartSec=0
ExecStartPre=-/usr/bin/docker kill hubot-redis
ExecStartPre=-/usr/bin/docker rm hubot-redis
ExecStartPre=/usr/bin/docker pull redis:latest
ExecStart=/usr/bin/docker run --name hubot-redis -v /var/lib/redis:/data redis:latest redis-server --save 600 1
ExecStop=/usr/bin/docker stop redis

只要你看一下,就会明白,在ExecStart中,我们以docker hub上公开的redis镜像为基础运行一个名为hubot-redis的容器。
另外,在启动之前,我们会先停止正在运行的容器,然后拉取最新的容器。

[Unit]
Description=Hubot
After=redis.service
Requires=redis.service

[Service]
TimeoutStartSec=0
ExecStartPre=-/usr/bin/docker kill hubot
ExecStartPre=-/usr/bin/docker rm hubot
ExecStartPre=/usr/bin/docker pull ymatsuwitter/hubot
ExecStart=/usr/bin/docker run --name hubot --link hubot-redis:redis ymatsuwitter/hubot
ExecStop=/usr/bin/docker stop hubot
User=core

由于Hubot依赖于Redis,所以在Unit部分声明了依赖关系。
除此之外,在其他地方通过”–link hubot-redis:redis”链接了Redis,这一点与之前不同。

我们试着部署这两个服务文件一次它们准备好了。

尝试使用 fleetctl 进行部署。

首先,我们要先登录到CoreOS,并在那里配置和运行service文件。但是,其实即使不登录,我们也可以使用fleetctl命令,所以让我们试着查看一下fleetctl的帮助信息吧。

在部署之前,如果你能把之前提到的两个service文件通过scp命令传输到CoreOS上,那就可以立即开始部署了。

$ fleetctl load redis.service
$ fleetctl start redis.service
$ fleetctl load hubot.service
$ fleetctl start hubot.service

只要执行这个它,hubot应该立即开始运行。
如果遇到任何问题,可以尝试使用fleetctl journal <service名称>.service命令来查看标准输出并进行确认。

将来部署时,构建并推送 Dockerfile。

$ fleetctl stop hubot.service
$ fleetctl start hubot.service

只要做完就可以了。

最后

这次在CoreOS上运行hubot的感想是,由于docker无法进行跨服务器的链接,所以只要解决这个问题(比如在AWS上使用私有DNS或使用Consul),就会是非常有潜力的工具。可能在kubernetes上也可以实现,但如果不考虑名称解析相关问题的话,fleet也是一个非常简单的工具,请务必试用一下。
未来,我也会公开一些相关的运维经验。

bannerAds