#この投稿について
Slack/Hubot/Dockerを用いたChatOpsでアプリの検証環境をポンポン作って、ポンポン捨てる方法をまとめます。
チャットから誰でも手軽に使い捨てのアプリの検証用環境を作成できるので、チーム開発の生産性向上が期待できます。
#システム構成の概要図
#システム構築手順
##SlackとHubotの連携
HubotをPaaSであるHerokuにデプロイさせ、Slackと連携させます。
こちらの具体的な手順については、「Slack / Hubot / GitHub / CircleCI によるChatOpsなデプロイ方法」の前半部分で詳しくまとめていますので、そちらを参照ください。
##Dockerを動かすサーバーの用意(EC2)
今回はAWSのEC2を用います。
###EC2の起動
まずは、Dockerを動かすインスタンスを立ち上げる。
今回はCommunityAMIの「ubuntu/images/hvm-ssd/ubuntu-trusty-14.04-amd64-server-20140927」というものを利用。
検証なので、インスタンスタイプはt2.micro
を選択。
インスタンスの名前は適当に分かりやすいものを付けておけばOK。
Security Groupの設定では、SSH用ポートの他に、追加で49153〜65535
ポートを解放しておく。
これはDockerのポートフォワーディングで使用されるポートである。
インスタンスが立ち上がれば、IPを確認してちゃんとSSH接続できるか確認。
ssh -i .ssh/docker-key.pem ubuntu@54.65.169.132
> ubuntu@ip-172-31-6-189:~ $
###ユーザーの作成
Dockerを操作する用のユーザーを作成する。ここではwanko
という名前で作成。
ubuntu:~$ sudo adduser wanko
Adding user `wanko' ...
Adding new group `wanko' (1001) ...
Adding new user `wanko' (1001) with group `wanko' ...
Creating home directory `/home/wanko' ...
Copying files from `/etc/skel' ...
Enter new UNIX password:
Retype new UNIX password:
passwd: password updated successfully
Changing the user information for wanko
Enter the new value, or press ENTER for the default
Full Name []:
Room Number []:
Work Phone []:
Home Phone []:
Other []:
Is the information correct? [Y/n] y
sudo権限を付与
ubuntu:~$ sudo usermod -G sudo wanko
パスワードレスでsudoになれるように設定
ubuntu:~$ sudo visudo
#以下を、追記
wanko ALL=(ALL) NOPASSWD: ALL
/etc/ssh/sshd_config
を変更して、パスワードによるログインを許可
ubuntu:~$ sudo vi /etc/ssh/sshd_config
#PasswordAuthentication no
PasswordAuthentication yes
変更した設定を反映するために、sshdを再起動
sudo service ssh restart
追加したユーザーでパスワードログインできるか確認
ssh wanko@54.65.169.132
wanko@54.65.169.132's password:
##GitHubにレポジトリ作成
今回はDockerのコンテナにGitHubからアプリをcloneしてきて動かしたいので、その検証用のレポジトリを作ります。
今回はHTMLだけのシンプルなアプリにしています。
実際のレポジトリ
https://github.com/s-kiriki/docker-test-app
また今回はChatOpsでブランチを自由に切り替えてDockerコンテナに任意のブランチをデプロイ出来るかを検証したいので、
以下の2つのブランチを用意しました。
・masterブランチ
シンプルに「Hello from Docker!」とだけ表示される実装
・add_imageブランチ
「Hello from Docker!」の下にDockerのイメージ(クジラのやつ)が表示される実装
##DockerホストOSの用意
上で立ち上げたインスタンスにDockerをインストールして、各種設定を行っていきます。
以下、このDockerのインストールされたインスタンスをDockerホストOSと書きます。
###Dockerのインストール
公式サイトに従ってインストールする。
sudo apt-get update
sudo apt-get install docker.io
インストールされたか確認
sudo docker --version
Docker version 1.0.1, build 990021a
Version1.3より追加されたdocker exec
を使いたいので、Dockerを最新版にUPDATE
curl -sSL https://get.docker.com/ubuntu/ | sudo sh
sudo docker --version
Docker version 1.4.0, build 4595d4f
###Dockerfileおよび、コンテナに転送するファイルの作成
Dockerfileを以下のように作成します。
FROM centos:centos6
RUN yum update -y
RUN yum install -y httpd
RUN yum install -y git
ADD ./app_init.sh /
RUN mkdir /root/.ssh/
ADD id_rsa /root/.ssh/id_rsa
RUN chmod 700 /root/.ssh/id_rsa
RUN echo -e "Host github.com\n\tStrictHostKeyChecking no\n" >> /root/.ssh/config
EXPOSE 80
CMD ["/usr/sbin/httpd", "-D", "FOREGROUND"]
ADD
コマンドで指定しているapp_init.sh
とid_rsa
はコンテナに転送するものですので、予め手元で作成にておく必要があります。
id_rsa
はGitHubに認証可能な秘密鍵で、app_init.sh
は以下のようなgit clone
で先ほどつくった検証用のレポジトリをcloneしてくるシェルスクリプトです。
#!/bin/bash
if [ $# -ne 1 ]; then
echo "You must specify branch name"
exit 1
fi
BRANCH_NAME=$1
cd /var/www/html && git clone -b $BRANCH_NAME --depth 1 git@github.com:s-kiriki/docker-test-app.git
###Dockerイメージの作成
上で作ったDockerfileよりDockerイメージを作成します。
今手元には、Dockerfile
、app_init.sh
、id_rsa
があることを確認してください。
wanko@ip-172-31-6-189:~$ ls
app_init.sh Dockerfile id_rsa
イメージの作成はdocker build
コマンドで行います。-t
オプションでイメージ名(今回はdocker-appとした)を指定し、最後の.
はDockerfile
のパス(今回はカレントディレクトリ)を指定しています。
$ sudo docker build -t docker_app .
Dockerイメージが作られたかをdocker image
コマンドで確認します。
$ sudo docker images
REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE
docker_app latest 6900f52b1ac5 5 seconds ago 466.5 MB
###コンテナの起動
上で作ったDockerイメージを使って、docker run
コマンドでコンテナを起動させます。
-d
オプションでApacheをデーモン化させ、-P
オプションでポートフォワーディングを行います。
$ sudo docker run -d -P docker_app
afbf3bd7c6be6e36ca436d34880b49970bacb25a72a9a351c9d3c28d5a8cd0a6
コンテナが作られたかは、docker ps
コマンドで確認できます。
$ sudo docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
afbf3bd7c6be docker_app:latest "/usr/sbin/httpd -D 2 minutes ago Up 2 minutes 0.0.0.0:49157->80/tcp kickass_brown
80番ポートが49157番ポートにポートフォワーディングされているのがわかります。
この状態で、http://54.65.169.132:49157/
(54.65.169.132の部分はDockerホストOSのアドレス)にアクセスすると、Apacheのホーム画面が表示されているはずです。
###アプリの設置
次に、このdocker run
で立ち上げたコンテナにアプリを設置します(GitHubからclone)。
コンテナに対してのコマンドの実行はdocker exec
コマンドで行えます。
今回はコンテナ側に既にあるapp_init.sh
を実行させればいいだけなので、以下のようにします。
$ sudo docker exec kickass_brown sh app_init.sh master
kickass_brown
はコンテナ名、master
はブランチ名
これでコンテナにアプリが設置されたので、http://54.65.169.132:49157/docker-test-app
にアクセスすると以下のようにアプリが動くはずです。
Dockerで起動させたコンテナでGitHub上のアプリが動きました!!
###ここまでのまとめ
ここでは、大きく分けて以下のようなことを行ってきました。
- Dockerのインストール
- Dockerfileの作成とアプリ設置シェルスクリプトの作成
- Dockerイメージの作成(
docker build
) - Dockerコンテナの起動(
docker run
) - アプリの設置(
docker exec
)
今回の最終目的はChatOps(Slackから指令を出す)で、指定のアプリの検証環境をポンポンつくること(コンテナをポンポン起動させること)であったので、この1~5の中の4と5をSlack経由で行う必要があります。
以降の節で、これらの方法を説明していきます。
##HubotからDockerコンテナの起動とアプリの設置を行う
SlackとHubot(Heroku上にデプロイ)の連携は既に済んでいるので、あとはHubotからDockerホストOSに命令を出してコンテナの起動とアプリの設置が行えれば、ChatOpsでアプリの検証環境を作れることになります。
この実装方法として、今回はDockerホストOSにDockerコンテナの起動とアプリの設置を行うシェルスクリプトを用意し、そのスクリプトをHubotからsshで接続して実行するという構成にしました。
###シェルスクリプトの用意(DockerホストOS)
DockerホストOSにDockerコンテナの起動とアプリの設置を行う以下のようなシェルスクリプトを用意します。
#!/bin/bash
if [ $# -ne 1 ]; then
echo "You must specify branch name"
exit 1
fi
BRANCH_NAME=$1
CONTAINER_ID=`sudo docker run -d -P docker_app` # コンテナの起動
if [ $? -ne 0 ]
then
echo "Error occured on running container."
exit 1
fi
echo "Created Container:$CONTAINER_ID"
PORT_FORWARDING=`sudo docker port $CONTAINER_ID`
if [ $? -ne 0 ]
then
echo "Error occured on checking port forwarding."
exit 1
fi
sudo docker exec $CONTAINER_ID sh app_init.sh $BRANCH_NAME # アプリの設置
if [ $? -ne 0 ]
then
echo "Error occured on setting app."
exit 1
fi
echo ":docker: Your app is ready!! $PORT_FORWARDING" # :docker: というのはSlackのカスタム絵文字
ポンポン作るだけではなく、ポンポン捨てることも目的だったので、同様にコンテナを削除するスクリプトも以下のように作ります。
#!/bin/bash
if [ $# -ne 1 ]; then
echo "You must specify container name or ID"
exit 1
fi
CONTAINER_ID=$1
REMOVED_CONTAINER=`sudo docker rm -f $CONTAINER_ID`
if [ $? -ne 0 ]
then
echo "Error occured on removing container $CONTAINER_ID."
exit 1
fi
echo ":docker: Removed container: $REMOVED_CONTAINER" # :docker: というのはSlackのカスタム絵文字
###Hubotスクリプトの作成
次に、DockerホストOSに設置したcontainer-up.sh
およびcontainer-remove.sh
をssh経由で実行するためのスクリプトをHubotに追加します。
simple-sshというnpmモジュールを使うのでインストールしておきます。
npm install simple-ssh --save
実際のコードは以下のようにしました。
# Description:
# Handling Docker containers.
#
# Dependencies:
# "simple-ssh": "^0.8.1"
# "hubot-slack": "^2.2.0"
#
# Configuration:
# [Required]
# DOCKER_HOST
# DOCKER_USER
# DOCKER_PASSWD
#
# Author:
# s-kiriki
module.exports = (robot) ->
_getSSH = (msg) ->
if !process.env.DOCKER_HOST
return msg.send 'You must set ENV: DOCKER_HOST'
if !process.env.DOCKER_USER
return msg.send 'You must set ENV: DOCKER_USER'
if !process.env.DOCKER_PASSWD
return msg.send 'You must set ENV: DOCKER_PASSWD'
SSH = require('simple-ssh');
ssh = new SSH({
host: process.env.DOCKER_HOST,
user: process.env.DOCKER_USER,
pass: process.env.DOCKER_PASSWD
});
return ssh
robot.respond /container up( (.+))?/i, (msg) ->
branch_name = msg.match[2] || "master"
ssh = _getSSH(msg)
ssh.exec("sh container-up.sh #{branch_name}", {
out: (stdout) ->
msg.send stdout
}).start();
robot.respond /container remove (\w+)/i, (msg) ->
container_id = msg.match[1]
ssh = _getSSH(msg)
ssh.exec("sh container-remove.sh #{container_id}", {
out: (stdout) ->
msg.send stdout
}).start();
robot.respond /container list/i, (msg) ->
ssh = _getSSH(msg)
ssh.exec("sudo docker ps | awk '{print $1, $(NF-1), $(NF)}'", {
out: (stdout) ->
msg.send stdout
}).start();
###Heroku上でHubotスクリプト用の環境変数をセット
hubot-container.coffee
ではDOCKER_HOST
、DOCKER_USER
、DOCKER_PASSWD
を環境変数でセットする必要があるので、これらをHeroku上で設置します。
##デモ
ようやく準備が整ったので、SlackからDockerを操作して検証環境をポンポン作ってみます。
###SlackとHubotの連携確認
まずは、ちゃんとSlackとHubotがうまく連携して動いてるか確認してみます。
ちゃんと動いてますね。ではいよいよ、コンテナを起動してアプリをデプロイしてみます。
###コンテナの起動とアプリのデプロイ
49160番ポートでコンテナが起動したようなので、http://54.65.169.132:49160/docker-test-app/
にアクセスしてみます。
うまく、アプリがデプロイされてます(ブランチが未指定の場合はmasterブランチがcloneされるようにしてある)。
では次に、別のブランチをデプロイしてみましょう。
49162番ポートでコンテナが起動したようなので、http://54.65.169.132:49162/docker-test-app/
にアクセスしてみます。
今度は、指定したとおりadd_image
ブランチの内容がデプロイされています。
###コンテナの削除
今度は不要なコンテナを削除してみます。
最初に49160番ポートで起動した方のコンテナを消してみます。
コンテナが削除され、http://54.65.169.132:49160/docker-test-app/
にアクセスしても接続できなくなっていることが確認できます。
###コンテナ一覧の確認
コンテナ一覧を確認できるコマンドも実装したので試してみます。
うまく表示されました!
以上長くなりましたが、Slack/Hubot/Dockerを使ったChatOpsでアプリの検証環境をポンポン作って、ポンポン捨てる方法についてまとめました。