Edited at

[Debian] chef/Serverspec のためだけに CoreOSのDockerを構成する [Wheezy]

More than 3 years have passed since last update.

流行に従って、Dockerを使い始めている最近です。どうせなら、CoreOS使ってやろうとCoreOS+Dockerで、chef/Serverspecの開発環境を作るに至ったのわけだけれども、systemd を初めて触ったり、/etc 配下をみてもサッパリ意味が分からなかったり、構成変更どうやったらいいのか、まるで宇宙に取り残された気分になりました。

そんな宇宙に取り残された状態でもNet上に散らばった情報をまとめていって、なんとか自分で満足のいくCoreOS+Docker環境が完成しました。

ので、自分のためだけに書き残しておきます。


CoreOSをインストールしよう

CDブートからCoreOSをインストールする方法を選択します。この1週間で10回以上はインストールしていますが、全てこの方法でクリーンインストールを繰り返しています。しかし、cloud-config.ymlという素敵な構成ファイルのお陰で、何度やりなおしても苦痛がないので助かっています。ホント素晴らしい。

さて、まずはメディアを準備しましょう。


ブートCDを準備する

Booting CoreOS from an ISO より好きなメディアを落としてきましょう、どうせイメージはネットからダウンロードしてインストールするので、どれでもいい気がします(個人的見解)。

仮想環境でも実機でもどこでもいいので、ISOのまま使うか、CDに焼くかは皆さんのお好み次第です。私は Proxmoxの仮想環境に入れてます。

起動するだけなら、ディスクサイズは2GBと必要ないでしょう。とは言え、イメージをおいたりするので、20-40GB と自分がどれだけのイメージを準備するかによって割り当てましょう。

我が家では、外部NFSをマウントしたりして、共有やデータの外部保管も実現してるので、16GBと少なめです。イメージ一つだけですしね。


cloud-config.yml を準備する

インストールする前に、まず設定ファイルを準備しておきます。面倒ごとは先にする主義です。実現してないけど。

内容はコレだ(ババン)長い


cloud-config.yml

#cloud-config

hostname: docker01.oshiire.to

coreos:
units:
- name: etcd.service
command: stop
- name: fleet.service
command: stop
- name: docker-tcp.socket
command: start
enable: yes
content: |
[Unit]
Description=Docker Socket for the Remote API

[Socket]
ListenStream=0.0.0.0:2375
Service=docker.service
BindIPv6Only=both

[Install]
WantedBy=sockets.target
- name: enable-docker-tcp.service
command: start
content: |
[Unit]
Description=Enable Docker Socket for Remote API

[Service]
type=oneshot
ExecStart=/usr/bin/systemctl enable docker-tcp.socket
- name: timezone.service
command: start
content: |
[Unit]
Description=timezone
[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/usr/bin/ln -sf ../usr/share/zoneinfo/Japan /etc/localtime
- name: 10-static.network
runtime: no
content: |
[Match]
Name=ens*

[Network]
Address=...
Gateway=...
DNS=...
- name: rpc-statd.service
command: start
- name: home.mount
command: start
content: |
[Unit]
Description=Home Directory on NFS
Before=rpc-statd.service
Conflicts=umount.target

[Mount]
What=...:/mnt/home
Where=/home
Options=rw,rsize=4096,wsize=4096,hard,intr,async,nodev,nosuid
Type=nfs
update:
reboot-strategy: best-effort

users:
- name: core
passwd: ...
groups:
- sudo
- docker
ssh-authorized-keys:
- ssh-rsa AAAA.....==


拡張子から分かるとおり、YAMLで記述されています。

個人的に見られたくない部分は「...」としています。主に書き換え必須な部分はそこだろうと当たりをつけてください。また、indent はスペースでないとダメらしいです。こわいですね。

さて、自分のために、全部説明書きを、残すんです(川平風)


#cloud-config


cloud-config.yml

#cloud-config


おまじないです。絶対に入れておいてください。ないと死にます。


hostname


cloud-config.yml

hostname: docker01.oshiire.to


家庭内で使っているホスト名なので、外から叩いても何も起きません。とりあえず、好きにつけてください。名前解決できるようにしておけるものが望ましいです。


coreos: units:

systemd で処理されるメインの部分です。

name: ごとに各daemon や service が割り当てられていると判断しました。(systemdがよく分かってない)


cloud-config.yml

coreos:

units:

おまじないです。忘れずに書きましょう。


cloud-config.yml

    - name: etcd.service

command: stop
- name: fleet.service
command: stop

etcd と fleet を使わないと心に誓った想いがここに現れています。

CoreOSとしては etcd/fleet がメインみたいなので、勝手に起動するように設定されそうなので先に排除しました。今回は Docker に絞ったのでこんな感じにしてます。


cloud-config.yml

    - name: docker-tcp.socket

command: start
enable: yes
content: |
[Unit]
Description=Docker Socket for the Remote API

[Socket]
ListenStream=0.0.0.0:2375
Service=docker.service
BindIPv6Only=both

[Install]
WantedBy=sockets.target
- name: enable-docker-tcp.service
command: start
content: |
[Unit]
Description=Enable Docker Socket for Remote API

[Service]
type=oneshot
ExecStart=/usr/bin/systemctl enable docker-tcp.socket


メイン部分の Docker 起動部分ですね。Docker プロセス自体は勝手に起動されてくるようなんですが、remote APIが使えないので、寂しすぎるので tcp socket サービスを入れて、外部からも docker コマンド を使えるようにしています。

ListenStream=0.0.0.0:2375 部分がキーポイントです。ListenするIPアドレスとポートを指定できます。このケースだと、IPv4 で割り当てられた全I/F から 2375/tcp ポートで待ち受けることを示してます。


timezone.service

どこからかパクってきました。最低です。

ここは日本であることを示して、Timezoneを設定してます。時刻は正しく表示してもらいたいですもんね!


cloud-config.yml

    - name: timezone.service

command: start
content: |
[Unit]
Description=timezone
[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/usr/bin/ln -sf ../usr/share/zoneinfo/Japan /etc/localtime


10-static.network

数字始まりでなにやら異質な部分ですが、ネットワーク設定部分です。


cloud-config.yml

    - name: 10-static.network

runtime: no
content: |
[Match]
Name=ens*

[Network]
Address=...
Gateway=...
DNS=...


[Network] 以下の Address=xxx.xxx.xxx.xxx/xx にIPアドレスを、Gateway=xxx.xxx.xxx.xxx に Default gatewayアドレスを、DNS=xxx.xxx.xxx.xxx に DNSサーバのIPアドレスを指定します。DNSが複数あるときは、もう1行 DNS=... を追加すれば良さそうです。


home.mount

我が家では慣習的に /home を nfsマウントして運用している手前、nfs マウントを追加しています。お好みですが、なかなか情報が無かったので、systemd の書き方探してきて、自分なりにアレンジしました。オレカッコイイ。


cloud-config.yml

    - name: rpc-statd.service

command: start
- name: home.mount
command: start
content: |
[Unit]
Description=Home Directory on NFS
Before=rpc-statd.service
Conflicts=umount.target

[Mount]
What=...:/mnt/home
Where=/home
Options=rw,rsize=4096,wsize=4096,hard,intr,async,nodev,nosuid
Type=nfs


nfs の lock サービスを使いたいので、rpc-statd を起動するようにしています。最初の2行がそれですね。

systemd の慣習として、xxx.mountxxx はマウント先を書くようなので、今回は home.mount としています。要するに好きにしろってコトです。

[Unit] 以下には、先に rpc-statd.service が起動していて欲しい、と言うことと、umount.target の仲間にして下さいと言うことで Conflicts を指定してます。詳しいことはよく分かりません。

[Mount] には、/etc/fstab に書いているようなことを記載します。

What は、マウント元です。...はマウント元のサーバ名またはIPアドレスで、: をはさんでディレクトリを示します。この例だと /mnt/home がマウント元のディレクトリですね。

Where は、このCoreOSでマウントする先になります。先にも説明したとおり、home を共有しているので、/homeとしています。この場合、CoreOS のホームディレクトリが /home 配下になりますので、その辺はうまいことやりましょう。

Options は、nfsのマウントオプションです。うちはこんな感じです。

Type には、マウントタイプを指定します。nfs じゃなくて smbfs や ext4 なども指定できますので、適宜読みかえましょう。


update

CoreOS はアップデートを見つけると勝手に更新して、勝手に再起動します。素敵ですね。

その時の再起動方針を指定します。


cloud-config.yml

  update:

reboot-strategy: best-effort

Using Cloud-Configupdate セクションに詳しいので、そちらを見てください。

なお、ぱくってくるとこんなコト書いてあります。


One of "reboot", "etcd-lock", "best-effort" or "off" for controlling when reboots are issued after an update is performed.


  • reboot: Reboot immediately after an update is applied.

  • etcd-lock: Reboot after first taking a distributed lock in etcd, this > guarantees that only one host will reboot concurrently and that the cluster will remain available during the update.

  • best-effort - If etcd is running, "etcd-lock", otherwise simply "reboot".

  • off - Disable rebooting after updates are applied (not recommended).


いつでもすぐに再起動して欲しければreboot、再起動して欲しくなければoff、なんだからよく分からなければbest-effort、etcd 使ってる人は etcd-lockbest-effortあたりで悩んでください。


users

長かった(個人的に)...。最後に usersです。CoreOSで利用するユーザをここに指定します。書かないとログインで困ります。


cloud-config.yml

users:

- name: core
passwd: ...
groups:
- sudo
- docker
ssh-authorized-keys:
- ssh-rsa AAAA.....==

name 欄にユーザ名を記載します

passwd には、Using Cloud-ConfigGenerating a password hash セクションにある方法で password のハッシュを作って、それを記載します。


commands

# On Debian/Ubuntu (via the package "whois")

mkpasswd --method=SHA-512 --rounds=4096

# OpenSSL (note: this will only make md5crypt. While better than antext it should not be considered fully secure)
openssl passwd -1

# Python (change password and salt values)
python -c "import crypt, getpass, pwd; print crypt.crypt('password', '\$6\$SALT\$')"

# Perl (change password and salt values)
perl -e 'print crypt("password","\$6\$SALT\$") . "\n"'


groups には所属グループを記載しますが、sudo に入れとかないとむせび泣くと思います

ssh-authorized-keys には、ssh の公開鍵をそのままぺたっと貼り付けます。我が家ではRSA鍵使ってるので、ssh-rsa から始まるあれが貼り付けてあります。これがそのまま ~/.ssh/authorized_keys になります。

長かった...。


インストールしよう!

の前に、コンソールで、上記 cloud-config.yml を入力するのは至難の業なので、次の順に進めていきます。



  1. core ユーザにパスワードをつける

  2. IPアドレスを知る

  3. 自由の利くクライアントから ssh ログインする


  4. cloud-config.yml をコピペするか、scp でコピーする

  5. インストールコマンドを打つ


1. core ユーザにパスワードをつける

起動した CoreOSでおもむろに次のコマンドを打ちましょう。


CoreOS

sudo passwd core


パスワードは好きにつけてください


2. IPアドレスを知る


CoreOS

ip -f inet addr


実は Enterキーを押しても IPアドレス分かります。何故こんなコトするかというと、dhcp で勝手に拾ってくるからです。dhcp ない人は諦めてください(やり方知らない)。


3. 自由の利くクライアントから ssh ログインする

先の二つの経験を元に


ssh

ssh core@[ipアドレス]


でどうぞ。~/.ssh/known_hosts が汚されたくない人は、-o "StrictHostKeyChecking no" つけてください。コレによる影響は多少は気にしたほうがいいです。


4. cloud-config.yml をコピペするか、scp でコピーする

多分 vi できますので、vi ~/cloud-config.yml したり、scp ./cloud-config.yml core@xxx.xxx.xxx.xxx:~/ で、先ほどの cloud-config.yml をなんとかしましょう。


5. インストールコマンドを打つ

最後です。これを打てばインストールできます。上記の設定で。素敵。


CoreOS

sudo coreos-install -d /dev/sda -C stable -c ~/cloud-config.yml -V 493.0.0


各オプションは次の通り

-d 導入先のディスクを指定します。

-C 導入する CoreOS のチャネルを指定します。stable(安定版) beta(β版) alpha(開発最新版) とあり、安定志向の人はstableを、最新版がとにかく使いたい人はalphaを、引っ込み思案で優柔不安なあなたはbetaを指定しましょう。

-c 大文字と小文字に注意。これまでがんばって作り上げたcloud-config.ymlファイルを指定します。

-V 導入するバージョンを指定します。個人的には指定した方が良いと思いますが、各チャネルの最新バージョンはRelease Channelsで確認できますので、ここを見ながら指定しましょう。


再起動

導入完了の合図がきたら、あとは再起動するのみです。

おめでとうございます、CoreOSの導入はここで完了です!

長かったなー。とお思いでしょうが、コレでは終わりません。大変です。


Debian用の chef/serverspec 用 Dockerイメージを準備する

なんだよ、フツーに docker build すればいいんだろと思われるかも知れませんが、実はちょっと注意事項があるんです。

私の Dockerfile をご覧に入れましょう。大盤振る舞いです。


Dockerfile

FROM debian:wheezy

MAINTAINER sho kisaragi <sho@oshiire.to>

RUN echo "deb http://ftp.jp.debian.org/debian/ wheezy main" > /etc/apt/sources.list
RUN echo "deb http://security.debian.org/ wheezy/updates main" >> /etc/apt/sources.list
RUN echo "deb http://ftp.jp.debian.org/debian/ wheezy-updates main" >> /etc/apt/sources.list

RUN apt-get update
RUN apt-get install -y ca-certificates dialog locales openssh-server sudo curl rsync net-tools --no-install-recommends
RUN apt-get upgrade -y && apt-get clean

RUN mkdir /var/run/sshd

RUN groupadd --gid 1000 chef
RUN useradd --uid 1000 --gid 1000 -m chef
RUN mkdir -p /home/chef/.ssh
RUN chmod 0700 /home/chef/.ssh
RUN chown chef.chef /home/chef/.ssh
RUN echo 'chef ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers.d/chef

ADD id_rsa.pub /home/chef/.ssh/authorized_keys
RUN chmod 0400 /home/chef/.ssh/authorized_keys
RUN chown chef.chef /home/chef/.ssh/authorized_keys

RUN echo "#!/bin/sh\nexit 0" > /usr/sbin/policy-rc.d

RUN curl -L https://www.opscode.com/chef/install.sh | sudo bash

EXPOSE 22

CMD ["/usr/sbin/sshd", "-D"]


何の変哲もない気がします。流れとしては、chefを実行するために必要なパッケージを入れることと、専用のユーザを準備しているだけに見えます。

残念、そうはいかないのです。


invoke-rc.d: policy-rc.d denied execution of start の罠

なんとなく docker上で chefを運用していると、invoke-rc.d: policy-rc.d denied execution of start. に巡り会い、service が起動できない自体に巡り会うことがあります。その理由は Docker, Openstack, policy-rc.d, mysqld にもある通り、systemd 化された CoreOSのために、policy-rc.d コマンドが exit 101 を強制的に返すことによる影響を受けるためです。分かっていればいいわけですが、地味にいやな気持ちになるので、Dockerfile 内に次の 1行を入れています。


Dockerfile

RUN echo "#!/bin/sh\nexit 0" > /usr/sbin/policy-rc.d


これでいいのか的な対応ですが、いいんです(川平風)

ここまでやって、やっと 「debian向けchef/serverspec開発用環境 on CoreOS」の完成です。

文章は無駄に長いですが、やってみると 5分で終わります。是非どうぞ。