【#Docker】Chef Zero を軽量インメモリ Chef Server として使い、ホスト OS から Docker コンテナを Chef で管理する #Chef #GetChef_ja

Chef Zero(chef-zero) を Chef Client のローカルモードではなく、軽量インメモリー Chef Server として使い、ホスト OS から Docker コンテナーを Chef で管理する手順を自分用のメモとしてまとめました。

Vagrant 上に作成した CentOS 7 環境を Docker のホスト OS として使用します。

Vagrant の Box は http://www.vagrantbox.es/ に公開されている以下を利用しました。

- [CentOS7.0 x86_64 minimal (VirtualBoxGuestAddtions 4.3.14)](https://f0fff3908f081cb6461b407be80daf97f07ac418.googledrive.com/host/0BwtuV7VyVTSkUG1PM3pCeDJ4dVE/centos7.box)

## 1: システムのアップデートと SELinux の無効化

まず、Docker を使用するためにパッケージのアップデートと SELinux の無効化を行います。

### 手順 1-1: Yum を使ってパッケージをアップデートします

```bash
[vagrant@localhost ~]$ sudo yum -y update
```

### 手順 1-2: SELinux を無効化します

```bash
[vagrant@localhost ~]$ sudo sed -i "s/^SELINUX=enforcing/SELINUX=disabled/g" /etc/selinux/config
[vagrant@localhost ~]$ grep "disabled" /etc/selinux/config

#     disabled - No SELinux policy is loaded.
SELINUX=disabled
```

→ 値が `disabled` になっていることを確かめます。

### 手順 1-3: OS を再起動します

```bash
[vagrant@localhost ~]$ sudo systemctl reboot
```

### 手順 1-4: SELinux が無効化されたことを確かめます

```bash
[vagrant@localhost ~]$ sudo /usr/sbin/sestatus

SELinux status:                 disabled
```

→ `disabled` と表示されることを確かめます。

## 2: Docker のセットアップ

Docker をセットアップします。

### 手順 2-1: Yum を使って Docker をインストールします

```bash
[vagrant@localhost ~]$ sudo yum -y install "docker"
[vagrant@localhost ~]$ rpm -qa | grep "docker"

docker-0.11.1-22.el7.centos.x86_64
```

### 手順 2-2: Docker のサービスを起動します

```bash
[vagrant@localhost ~]$ sudo systemctl start "docker.service"
[vagrant@localhost ~]$ sudo systemctl enable "docker.service"
[vagrant@localhost ~]$ systemctl list-units | grep "docker.service"

sys-devices-virtual-net-docker0.device
          loaded active plugged   /sys/devices/virtual/net/docker0
sys-subsystem-net-devices-docker0.device
          loaded active plugged   /sys/subsystem/net/devices/docker0
var-lib-docker.mount
          loaded active mounted   /var/lib/docker
docker.service
          loaded active running   Docker Application Container Engine
```

→ 上記のように表示されれば成功です。

### 手順 2-3: Docker がセットアップされたことを確認します

```bash
[vagrant@localhost ~]$ sudo docker version

Client version: 0.11.1-dev
Client API version: 1.12
Go version (client): go1.2
Git commit (client): 02d20af/0.11.1
Server version: 0.11.1-dev
Server API version: 1.12
Go version (server): go1.2
Git commit (server): 02d20af/0.11.1
```

→ 上記のように表示されれば成功です。

## 3: Chef Zero のセットアップ

続いて、Chef Zero を軽量インメモリー Chef Server として使えるようにセットアップします。

### 手順 3-1: Yum を使って Git と ChefDK をインストールします

```bash
[vagrant@localhost ~]$ sudo yum -y install "git" "https://packagecloud.io/chef/stable/download?distro=6&filename=chefdk-0.2.2-1.x86_64.rpm"
[vagrant@localhost ~]$ rpm -qa | egrep "git-|chefdk"

git-1.8.3.1-4.el7.x86_64
chefdk-0.2.2-1.x86_64
```

### 手順 3-2: Git を使って `chef-repo` （ローカルリポジトリのひな形）をダウンロードします

```bash
[vagrant@localhost ~]$ cd ~
[vagrant@localhost ~]$ git clone "git://github.com/opscode/chef-repo.git"
```

### 手順 3-3: `chef-repo` 下に `.chef` ディレクトリを作成します

```bash
[vagrant@localhost ~]$ mkdir -p ~/chef-repo/.chef
[vagrant@localhost ~]$ ls -ld ~/chef-repo/.chef/

drwxrwxr-x 2 vagrant vagrant 6 Xxx XX XX:XX /home/vagrant/chef-repo/.chef/
```

### 手順 3-4: ネットワークインターフェース `docker0` に割り当てられた IP アドレスを確認します

```bash
[vagrant@localhost ~]$ ip address show "docker0"

4: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN
    link/ether 56:84:7a:fe:97:99 brd ff:ff:ff:ff:ff:ff
    inet 172.17.42.1/16 scope global docker0
       valid_lft forever preferred_lft forever
```

→ `172.17.42.1` が割り当てられていることを確認します。

### 手順 3-5: Knife の設定ファイル `knife.rb` を作成します

```bash
[vagrant@localhost ~]$ cat << EOF | tee ~/chef-repo/.chef/knife.rb
current_dir = File.dirname(__FILE__)
chef_server_url "http://172.17.42.1:8889"
node_name "$(nmcli general hostname)"
client_key "#{current_dir}/dummy.pem"
cookbook_path "#{current_dir}/../cookbooks"
EOF
```

### 手順 3-6: Chef Zero を Systemd のユニットとして登録します

```bash
[vagrant@localhost ~]$ sudo sh -c "cat << EOF | tee /etc/systemd/system/chef-zero.service
[Unit]
Description=chef-zero

[Service]
Type=simple
User=daemon
Environment=PATH=/opt/chefdk/embedded/bin
ExecStart=/opt/chefdk/embedded/bin/chef-zero -H 172.17.42.1 -p 8889
Restart=always

[Install]
WantedBy=multi-user.target
EOF"
```

### 手順 3-7: `/etc/services` を編集します

```bash
[vagrant@localhost ~]$ sudo vi /etc/services
```

→ 次の 1 行を適切な箇所に追記します。

```
chef-zero       8889/tcp                        # Chef Zero
```

### 手順 3-8: RSA 秘密鍵（pem ファイル）を作成します

```bash
[vagrant@localhost ~]$ ssh-keygen -t rsa -N "" -f ~/chef-repo/.chef/dummy.pem
[vagrant@localhost ~]$ ls -l ~/chef-repo/.chef/dummy.pem

-rw------- 1 vagrant vagrant XXXX Xxx XX XX:XX /home/vagrant/chef-repo/.chef/dummy.pem
```

→ ダミーのファイルですが、中身は RSA 秘密鍵の形式である必要があります。

### 手順 3-9: `/etc/chef` ディレクトリを作成します

```bash
[vagrant@localhost ~]$ sudo mkdir -p /etc/chef
[vagrant@localhost ~]$ ls -ld /etc/chef/

drwxr-xr-x 2 root root 6 Xxx XX XX:XX /etc/chef/
```

### 手順 3-10: RSA 秘密鍵（pem ファイル）のシンボリックリンクを作成します

```bash
[vagrant@localhost ~]$ sudo ln -sf ~/chef-repo/.chef/dummy.pem /etc/chef/validation.pem
[vagrant@localhost ~]$ ls -l /etc/chef/validation.pem

lrwxrwxrwx 1 root root 39 Xxx XX XX:XX /etc/chef/validation.pem -> /home/vagrant/chef-repo/.chef/dummy.pem
```

### 手順 3-11: Systemd を使って Chef Zero のサービスを起動します。

```bash
[vagrant@localhost ~]$ sudo systemctl start "chef-zero.service"
[vagrant@localhost ~]$ sudo systemctl enable "chef-zero.service"
[vagrant@localhost ~]$ systemctl list-units | grep "chef-zero.service"

chef-zero.service
          loaded active running   chef-zero
```

### 手順 3-12: リスニングポートの状態を確認します 

```bash
[vagrant@localhost ~]$ sudo ss -lp | grep "chef-zero"

tcp    LISTEN     0      128        172.17.42.1:chef-zero               *:*        users:(("ruby",XXXX,7))
```

### 手順 3-13: Knife を使って Chef Zero との接続を確認します

```bash
[vagrant@localhost ~]$ cd ~/chef-repo/
[vagrant@localhost ~]$ knife client list

chef-validator
chef-webui
```

→ 上記のように表示されれば成功です。

### 手順 3-11: FirewallD サービスを停止します。

```bash
[vagrant@localhost ~]$ sudo systemctl stop "firewalld.service"
[vagrant@localhost ~]$ sudo systemctl disable "firewalld.service"
[vagrant@localhost ~]$ systemctl list-units | grep "firewalld.service"
```

→ 何も表示されない事を確かめます。

本来であれば、FirewallD も正しく設定すべきですが、ここでは手順簡略化のためにサービスごと停止してしまいます。

## 4: Docker コンテナーに適用するクックブックの作成

ここでは、コミュニティに公開されているクックブック `Apache2` をラップするだけの簡単なクックブックを作成します。

### 手順 4-1: Cookbook の置き場を作成します

```bash
[vagrant@localhost ~]$ mkdir -p ~/chef-repo/site-cookbooks
[vagrant@localhost ~]$ ls -ld ~/chef-repo/site-cookbooks/

drwxrwxr-x 2 vagrant vagrant 6 Xxx XX XX:XX /home/vagrant/chef-repo/site-cookbooks/
```

### 手順 4-2: berks コマンドを使って `HTTP_server` という名前のクックブックを作成します

```bash
[vagrant@localhost ~]$ cd ~/chef-repo/site-cookbooks/
[vagrant@localhost ~]$ chef exec berks cookbook "HTTP_server" --skip-vagrant --skip-test-kitchen  --license="reserved" --maintainer="YOUR_NAME" --maintainer-email="YOUR_EMAIL"
[vagrant@localhost ~]$ ls -ld ~/chef-repo/site-cookbooks/HTTP_server/

drwxrwxr-x 10 vagrant vagrant 4096 Xxx XX XX:XX /home/vagrant/chef-repo/site-cookbooks/HTTP_server/
```

### 手順 4-3: Cookbook のメタデータ設定ファイル `metadata.rb` を編集します

```bash
[vagrant@localhost ~]$ echo "depends 'apache2'" | tee -a HTTP_server/metadata.rb
```

```rb:metadata.rb
name             'HTTP_server'
maintainer       'YOUR_NAME'
maintainer_email 'YOUR_EMAIL'
license          'All rights reserved'
description      'Installs/Configures HTTP_server'
long_description 'Installs/Configures HTTP_server'
version          '0.1.0'
depends 'apache2'
```

### 手順 4-4: Cookbook のデフォルトレシピファイル `default.rb` を編集します

```bash
[vagrant@localhost ~]$ echo "include_recipe 'apache2::default'" | tee -a HTTP_server/recipes/default.rb
```

```rb:default.rb
#
# Cookbook Name:: HTTP_server
# Recipe:: default
#
# Copyright (C) 2014 YOUR_NAME
#
# All rights reserved - Do Not Redistribute
#
include_recipe 'apache2::default'
```

### 手順 4-5: Berkshelf を使って依存関係のあるクックブックをダウンロードします

```bash
[vagrant@localhost ~]$ cd ~/chef-repo/site-cookbooks/HTTP_server/
[vagrant@localhost ~]$ chef exec berks vendor
[vagrant@localhost ~]$ ls -l berks-cookbooks/

total 16
drwxrwxr-x 7 vagrant vagrant  138 Xxx XX XX:XX apache2
-rw------- 1 vagrant vagrant  256 Xxx XX XX:XX Berksfile.lock
drwxrwxr-x 9 vagrant vagrant 4096 Xxx XX XX:XX HTTP_server
drwxrwxr-x 6 vagrant vagrant  126 Xxx XX XX:XX iptables
drwxrwxr-x 7 vagrant vagrant 4096 Xxx XX XX:XX logrotate
drwxrwxr-x 6 vagrant vagrant 4096 Xxx XX XX:XX pacman
```

### 手順 4-6: 作成したクックブックを Chef Zero にアップロードします

```bash
[vagrant@localhost ~]$ chef exec berks upload
[vagrant@localhost ~]$ knife cookbook list

HTTP_server   0.1.0
apache2       2.0.0
iptables      0.14.0
logrotate     1.7.0
pacman        1.1.1
```

→ 上記のように表示されれば成功です。

## 5: Docker コンテナーイメージの作成

### 手順 5-1: `Dockerfile` を作成します

```bash
[vagrant@localhost ~]$ cat << EOF | tee ~/chef-repo/.chef/Dockerfile
FROM centos:centos6
RUN yum -y update
RUN curl https://www.getchef.com/chef/install.sh | bash
RUN knife configure client -s 'http://172.17.42.1:8889' '/etc/chef/'
ADD dummy.pem /etc/chef/validation.pem
EOF
```

### 手順 5-2: 作成した `Dockerfile` を使ってコンテナーイメージをビルドします

```bash
[vagrant@localhost ~]$ cd ~/chef-repo/.chef/
[vagrant@localhost ~]$ sudo docker build -t chef-node:centos6 .
[vagrant@localhost ~]$ sudo docker images


REPOSITORY          TAG                 IMAGE ID            CREATED             VIRTUAL SIZE
chef-node           centos6             fa91934382b6        53 seconds ago      409.8 MB
centos              centos6             68eb857ffb51        2 weeks ago         212.7 MB
```

→ 上記のように表示されれば成功です。

## 6: Docker コンテナーの作成とクックブックの適用

### 手順 6-1: 念のため起動している全ての Docker コンテナーを削除します

```bash
[vagrant@localhost ~]$ sudo docker stop $(sudo docker ps -q)
[vagrant@localhost ~]$ sudo docker rm $(sudo docker ps -a -q)
[vagrant@localhost ~]$ sudo docker ps -a

CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS
        NAMES
```

### 手順 6-2: 試しに 2 台のコンテナーを起動します

```bash
[vagrant@localhost ~]$ sudo docker run -d -p 8001:80 chef-node:centos6 chef-client -i 600 -s 60 -N "node_01"
[vagrant@localhost ~]$ sudo docker run -d -p 8002:80 chef-node:centos6 chef-client -i 600 -s 60 -N "node_02"
[vagrant@localhost ~]$ sudo docker ps

CONTAINER ID        IMAGE               COMMAND                CREATED             STATUS              PORTS
              NAMES
xxxxxxxxx        chef-node:latest    chef-client -i 60 -s   XX seconds ago      Up XX seconds       0.0.0.0:8002->80/tcp   xxxxxxxxx
xxxxxxxxx        chef-node:latest    chef-client -i 60 -s   XX seconds ago      Up XX seconds       0.0.0.0:8001->80/tcp   xxxxxxxxx
```

### 手順 6-2: Knife を使って起動したコンテナーが Chef の Node として登録されたことを確かめます

```bash
[vagrant@localhost ~]$ knife node list

node_01
node_02
```

### 手順 6-2: コンテナーに クックブック `HTTP_server` のレシピを適用します

```bash
[vagrant@localhost ~]$ knife node run_list add "node_01" "HTTP_server"

node_01:
  run_list: recipe[HTTP_server]
```
```bash
[vagrant@localhost ~]$ knife node run_list add "node_02" "HTTP_server"

node_02:
  run_list: recipe[HTTP_server]
```

### 手順 6-3: しばらくすると `httpd` デーモンプロセスが立ち上がってきます

```bash
[vagrant@localhost ~]$ watch "ps aux | grep httpd"

Every 2.0s: ps aux | grep httpd                                                         Xxx Xxx XX XX:XX:XX XXXX
root     29179  0.0  0.0      0     0 ?        Zs   21:06   0:00 [httpd] <defunct>
48       29473  0.0  0.0 107204  2108 ?        S    21:06   0:00 /usr/sbin/httpd
48       29474  0.0  0.0 107204  2108 ?        S    21:06   0:00 /usr/sbin/httpd
48       29476  0.0  0.0 107204  2108 ?        S    21:06   0:00 /usr/sbin/httpd
48       29478  0.0  0.0 107204  2108 ?        S    21:06   0:00 /usr/sbin/httpd
48       29479  0.0  0.0 107204  2108 ?        S    21:06   0:00 /usr/sbin/httpd
root     31033  0.0  0.0      0     0 ?        Zs   21:16   0:00 [httpd] <defunct>
48       31485  0.0  0.0 107204  2112 ?        S    21:17   0:00 /usr/sbin/httpd
48       31486  0.0  0.0 107204  2112 ?        S    21:17   0:00 /usr/sbin/httpd
48       31487  0.0  0.0 107204  2112 ?        S    21:17   0:00 /usr/sbin/httpd
48       31488  0.0  0.0 107204  2112 ?        S    21:17   0:00 /usr/sbin/httpd
48       31489  0.0  0.0 107204  2112 ?        S    21:17   0:00 /usr/sbin/httpd
vagrant  31810  0.2  0.0 116928  1616 pts/0    S+   21:19   0:00 watch ps aux | grep httpd
vagrant  31819  0.0  0.0 116924   444 pts/0    S+   21:20   0:00 watch ps aux | grep httpd
vagrant  31820  0.0  0.0 113116  1360 pts/0    S+   21:20   0:00 sh -c ps aux | grep httpd
vagrant  31822  0.0  0.0 112640   944 pts/0    S+   21:20   0:00 grep httpd
```

---

ちょっと試し方が思いつかなかったのですが、これでコンテナー上の `httpd` サービスが停止しても Chef Client が検知しサービスが再起動します。

以上が Chef Zero を使い、ホスト OS から Docker のコンテナーを Chef で管理する手順でした。