めもめも

このブログに記載の内容は個人の見解であり、必ずしも所属組織の立場、戦略、意見を代表するものではありません。

OpenStack上でRHEL7のDockerを使う手順

このエントリーは、2015/11/04に開催のRed Hat Forum 2015の「Red Hat Enterprise Linux OpenStack Platform環境でのDocker活用テクニック」というセッションで説明する内容のメモ書きです。この内容をもっと詳しく(分かりやすく)聞きたいという方は、こちらのセッションにお越しください。登録時の招待コードは「300」です。

事前準備

取り急ぎのメモ書き・・・。CentOS7でも本質的には同じです。CentOS7の場合は、subscription-managerコマンドは無視してください。

はじめに、RHEL7のクラウドイメージをCustomer Portalからダウンロードして、Glanceに登録しておきます。

Dockerのイメージ保存領域を追加のエフェメラルディスクに配置するので、追加のエフェメラルディスク(とついでにSwap領域)を持ったフレーバー m1.docker を定義しておきます。

# nova flavor-show m1.docker
+----------------------------+--------------------------------------+
| Property                   | Value                                |
+----------------------------+--------------------------------------+
| OS-FLV-DISABLED:disabled   | False                                |
| OS-FLV-EXT-DATA:ephemeral  | 20    <---ココが重要                  |
| disk                       | 10                                   |
| extra_specs                | {}                                   |
| id                         | a385b85b-8efd-4149-a914-4d870f09af9b |
| name                       | m1.docker                            |
| os-flavor-access:is_public | True                                 |
| ram                        | 1024                                 |
| rxtx_factor                | 1.0                                  |
| swap                       | 2048     <---ココが重要               |          
| vcpus                      | 1                                    |
+----------------------------+--------------------------------------+

RHEL7のイメージからVMインスタンスを起動してログインしたら、下記のコマンドでDockerを導入します。

# subscription-manager register
# subscription-manager attach --pool=<pool id>
# subscription-manager repos --disable=*
# subscription-manager repos --enable=rhel-7-server-rpms --enable=rhel-7-server-extras-rpms
# yum -y update
# yum -y install docker lvm2

この状態でインスタンスを停止(削除ではないですよ!)して、スナップショットを作成しておきます。(スナップショットを作成する前のゴミ掃除は適当にお願いします。)

# glance image-list
+--------------------------------------+------------------+-------------+------------------+------------+--------+
| ID                                   | Name             | Disk Format | Container Format | Size       | Status |
+--------------------------------------+------------------+-------------+------------------+------------+--------+
| d6bd60e9-be04-4610-8cad-c3644182fa69 | RHEL7.1          | qcow2       | bare             | 425956864  | active |
| cdcc6a27-c88f-4032-87a9-1370ea89d0ff | RHEL7_Docker     | qcow2       | bare             | 1449000960 | active |
+--------------------------------------+------------------+-------------+------------------+------------+--------+

VMインスタンスの起動

先ほど保存したスナップショットからインスタンスを起動して、UserDataで、下記のスクリプトを流します。フレーバーは事前に用意したm1.dockerを使用してください。/etc/sysconfig/dockerと/etc/hostsの設定は、プライベートレジストリー(192.168.1.101)を参照するためのものです。

#!/bin/bash -x

cat <<'EOF' >>/etc/sysconfig/docker
INSECURE_REGISTRY='--insecure-registry registry01:5000'
EOF
cat <<'EOF' >>/etc/hosts
192.168.1.101 registry01
EOF

umount /mnt
sed -i 's/^\/dev\/vdb/#\/dev\/vdb/' /etc/fstab
cat <<'EOF' >/etc/sysconfig/docker-storage-setup
VG=vg_pool
DATA_SIZE=18G
EOF
systemctl stop --no-block docker.service
rm -rf /var/lib/docker/*
pvcreate -f /dev/vdb
vgcreate vg_pool /dev/vdb
docker-storage-setup

systemctl start --no-block docker.service

この後、インスタンスにログインすれば、普通にdockerコマンドが使えます。

# docker info
Containers: 0
Images: 0
Storage Driver: devicemapper
 Pool Name: vg_pool-docker--pool
 Pool Blocksize: 524.3 kB
 Backing Filesystem: xfs
 Data file: 
 Metadata file: 
 Data Space Used: 20.45 MB
 Data Space Total: 19.33 GB
 Data Space Available: 19.31 GB
 Metadata Space Used: 49.15 kB
 Metadata Space Total: 25.17 MB
 Metadata Space Available: 25.12 MB
 Udev Sync Supported: true
 Deferred Removal Enabled: true
 Library Version: 1.02.93-RHEL7 (2015-01-28)
Execution Driver: native-0.2
Logging Driver: json-file
Kernel Version: 3.10.0-229.14.1.el7.x86_64
Operating System: Employee SKU
CPUs: 1
Total Memory: 993.3 MiB
Name: docker02.novalocal
ID: LT2Y:LJKF:JZRM:C3RH:U4BK:K6IK:3AMS:BESA:DAFO:NMDJ:FCED:HI6Z

UserDataからコンテナを起動する方法

これには、実は少しトリックが必要です・・・・。

UserDataを実行するcloud-init.serviceは、systemdのサービスとして実行しているため、この中で発行した "systemctl start --no-block docker.service" は、UserDataの実行が完了するまで実際の実行が行われません。つまり、UserDataの中で、docker.serviceの起動完了を待って、"docker run"を実行するという処理ができないのです。

ここでは、「docker.serviceの起動完了を待って、"docker run"を実行する」というスクリプトをその場で作って、バックグラウンドで実行しておくという作戦を取ります。具体的には、次のようなUserDataになります。

#!/bin/bash -x

# Settings for the private registry
cat <<'EOF' >>/etc/sysconfig/docker
INSECURE_REGISTRY='--insecure-registry registry01:5000'
EOF
cat <<'EOF' >>/etc/hosts
192.168.1.101 registry01
EOF

# Setting up the local storage
umount /mnt
sed -i 's/^\/dev\/vdb/#\/dev\/vdb/' /etc/fstab
cat <<'EOF' >/etc/sysconfig/docker-storage-setup
VG=vg_pool
DATA_SIZE=18G
EOF
rm -rf /var/lib/docker/*
pvcreate -f /dev/vdb
vgcreate vg_pool /dev/vdb
docker-storage-setup

# Starting the docker service and a container
systemctl --no-block start docker.service
cat <<'EOF' >/tmp/run_container$$.sh
#!/bin/bash
while [[ true ]]; do
  sleep 5
  systemctl is-active docker.service && break
done
docker run -itd -p 8000:80 --name dengonban01 registry01:5000/enakai00/rails:ver1.0
EOF
chmod u+x /tmp/run_container$$.sh
/tmp/run_container$$.sh 2>&1 | logger -t run_container$$ &

うーん。もうちょっとすっきりできないですかね。

と思いつつ次の手順へ。

単一コンテナのアプリを起動する

Docker実践入門――Linuxコンテナ技術の基礎から応用まで (Software Design plus)
「Docker実践入門」の「2.2.2 Dockerfileとシェルスクリプトの連携」で紹介されている伝言板アプリのコンテナを起動してみます。ここでは、書籍の手順で作成したイメージをプライベートレジストリーに「registry01:5000/enakai00/dengonban:ver1.0」として保存してあるものとします。(プライベートレジストリーのセットアップ方法などは、書籍を参照してくださいね!)

まず、UserDataで使用する次のスクリプトを用意します。

dengonban.txt

#!/bin/bash -x

# Settings for the private registry
cat <<'EOF' >>/etc/sysconfig/docker
INSECURE_REGISTRY='--insecure-registry registry01:5000'
EOF
cat <<'EOF' >>/etc/hosts
192.168.1.101 registry01
EOF

# Setting up the local storage
umount /mnt
sed -i 's/^\/dev\/vdb/#\/dev\/vdb/' /etc/fstab
cat <<'EOF' >/etc/sysconfig/docker-storage-setup
VG=vg_pool
DATA_SIZE=18G
EOF
rm -rf /var/lib/docker/*
pvcreate -f /dev/vdb
vgcreate vg_pool /dev/vdb
docker-storage-setup

# Starting the docker service and a container
systemctl --no-block start docker.service
cat <<'EOF' >/tmp/run_container$$.sh
#!/bin/bash
while [[ true ]]; do
  sleep 5
  systemctl is-active docker.service && break
done
docker run -itd -p 8000:80 --name dengonban01 registry01:5000/enakai00/rails:ver1.0
EOF
chmod u+x /tmp/run_container$$.sh
/tmp/run_container$$.sh 2>&1 | logger -t run_container$$ &

次のコマンドでVMインスタンスを起動します。(オプションは環境に応じて、適当に変えてください。)

# nova boot --flavor m1.docker --image RHEL7_Docker --key-name mykey \
  --security-groups default --nic net-id=4edf131f-eb31-4121-b754-3b15769bf468 \
  --user-data dengonban.txt dengonban01
# nova add-floating-ip dengonban01 192.168.1.102

インスタンスが起動すると、プライベートレジストリーからイメージを取得して、自動的にコンテナが起動します。ブラウザから「http://192.168.1.102:8000」にアクセスすると伝言板が利用できます。(セキュリティグループは、8000番ポートの接続を許可しておいてください。)

複数コンテナの連携アプリを起動する

Docker実践入門――Linuxコンテナ技術の基礎から応用まで (Software Design plus)
「Docker実践入門」の「2.3 複数コンテナーの連携活用」で紹介されている短縮URLサービスアプリのコンテナを起動します。これは、バックエンドのMySQLとフロントエンドのnode.jsアプリが連携するシステムです。それぞれ、異なるVMインスタンス上でコンテナを起動して連携させてみます。また、MySQLについては、Cinderボリュームの中にテーブルデータを保存するように構成します。

MySQLとnode.jsアプリのイメージは、書籍の手順で作成して、プライベートレジストリーに「registry01:5000/enakai00/mysql:ver1.0」「registry01:5000/enakai00/shorturl:ver1.0」として保存してあるものとします。

MySQLは、次のUserDataで起動します。

mysql.txt

#!/bin/bash -x

# Settings for the private registry
cat <<'EOF' >>/etc/sysconfig/docker
INSECURE_REGISTRY='--insecure-registry registry01:5000'
EOF
cat <<'EOF' >>/etc/hosts
192.168.1.101 registry01
EOF

# Setting up the local storage
umount /mnt
sed -i 's/^\/dev\/vdb/#\/dev\/vdb/' /etc/fstab
cat <<'EOF' >/etc/sysconfig/docker-storage-setup
VG=vg_pool
DATA_SIZE=18G
EOF
rm -rf /var/lib/docker/*
pvcreate -f /dev/vdb
vgcreate vg_pool /dev/vdb
docker-storage-setup

# Starting the docker service and a container
systemctl --no-block start docker.service

cat <<'EOF' >/tmp/run_container$$.sh
#!/bin/bash
while [[ true ]]; do
  sleep 5
  systemctl is-active docker.service && break
done

# Wait until the cinder volume becomes available.
while [[ true ]]; do
  sleep 5
  if lsblk | grep '^vdd'; then
    break
  fi
done

# Mount the cinder volume on /data.
mkfs.xfs -f /dev/vdd
mkdir /data
mount /dev/vdd /data
mkdir /data/mysql01
chcon -Rt svirt_sandbox_file_t /data

# Start the container and mysqld service.
docker run -itd --name mysql01 -v /data/mysql01:/var/lib/mysql -p 10000:3306 registry01:5000/enakai00/mysql:ver1.0
while [[ true ]]; do
  sleep 5
  if docker exec mysql01 mysql -u root -e "show databases;"; then
    break
  fi
done
docker exec mysql01 mysql -u root -e "GRANT ALL PRIVILEGES ON *.* TO 'nodeuser'@'localhost';"
docker exec mysql01 mysql -u root -e "GRANT ALL PRIVILEGES ON *.* TO 'nodeuser'@'%' IDENTIFIED BY 'pas4mysql';"
docker exec mysql01 mysql -u nodeuser -e "CREATE DATABASE shorturl_service;"
docker exec mysql01 mysql shorturl_service -u nodeuser -e " \
CREATE TABLE url_list ( \
hash CHAR(12) PRIMARY KEY, \
url VARCHAR(256) UNIQUE NOT NULL COLLATE utf8_bin \
);"
EOF

chmod u+x /tmp/run_container$$.sh
/tmp/run_container$$.sh 2>&1 | logger -t run_container$$ &

コンテナの起動スクリプトでは、Cinderボリュームが/dev/vddとして認識されるのを待って、その後、ボリュームのフォーマット/マウントを行い、これをコンテナ内の/var/lib/mysqlに割り当てています。コンテナ起動後に、MySQLのデータベースの初期化を行っています。エラー処理などは省略していますので、そのあたりは、突っ込まないでください。

次のコマンドで、VMインスタンスの起動とCinderボリュームのアタッチを行います。

# nova boot --flavor m1.docker --image RHEL7_Docker --key-name mykey \
  --security-groups default --nic net-id=4edf131f-eb31-4121-b754-3b15769bf468 \
  --user-data mysql.txt mysql01
# nova add-floating-ip mysql01 192.168.1.104
# nova volume-attach mysql01 03e12c55-5a0e-4630-a630-2d34283144ed

コンテナが起動すると、外部からは、10000番ポートでMySQLに接続可能になります。(セキュリティグループで、10000番ポートへの接続を許可しておいてください。)

この次は、node.jsアプリのコンテナを起動します。次のUserDataを使用します。

shorturl.txt

#!/bin/bash -x

# Settings for the private registry
cat <<'EOF' >>/etc/sysconfig/docker
INSECURE_REGISTRY='--insecure-registry registry01:5000'
EOF
cat <<'EOF' >>/etc/hosts
192.168.1.101 registry01
EOF

# Setting up the local storage
umount /mnt
sed -i 's/^\/dev\/vdb/#\/dev\/vdb/' /etc/fstab
cat <<'EOF' >/etc/sysconfig/docker-storage-setup
VG=vg_pool
DATA_SIZE=18G
EOF
rm -rf /var/lib/docker/*
pvcreate -f /dev/vdb
vgcreate vg_pool /dev/vdb
docker-storage-setup

# Starting the docker service and a container
systemctl --no-block start docker.service

cat <<'EOF' >/tmp/run_container$$.sh
#!/bin/bash
while [[ true ]]; do
  sleep 5
  systemctl is-active docker.service && break
done

# Start the container and mysqld service.
docker run -itd --name shorturl01 -p 8000:80 \
  -e DB_PORT_3306_TCP_ADDR=192.168.1.104 \
  -e DB_PORT_3306_TCP_PORT=10000 \
  registry01:5000/enakai00/shorturl:ver1.0
EOF

chmod u+x /tmp/run_container$$.sh
/tmp/run_container$$.sh 2>&1 | logger -t run_container$$ &

次のコマンドでVMインスタンスを起動します。

# nova boot --flavor m1.docker --image RHEL7_Docker --key-name mykey \
  --security-groups default --nic net-id=4edf131f-eb31-4121-b754-3b15769bf468 \
  --user-data shorturl.txt shorturl01
# nova add-floating-ip shorturl01 192.168.1.105

コンテナが起動したら、WebブラウザでURL「http://192.168.1.105:8000」にアクセスすると、短縮URLサービスが利用できます。