文系プログラマによるTIPSブログ

文系プログラマ脳の私が開発現場で学んだ事やプログラミングのTIPSをまとめています。

docker image版amazonlinuxをec2版amazonlinuxのように使ってansibleでプロビジョニングする

目的が違うのに強引過ぎるだろ〜

f:id:treeapps:20171024021654p:plain

オンプレからAWSに移行(しかもオートスケール構成にしにくい負債プロジェクトとか・・・)する際に、dockerではなくec2を使う場合、ローカルはどうするか。できればdockerにしたいですよね。

amazonlinuxのdocker imageはamazonが公式に提供しているので、これを使いたいですね。
https://hub.docker.com/_/amazonlinux/
amazonlinuxでないと、yum.repoでインストールできるバージョンが全然違いますし、apache2.4なんかは実はamazonエディションだったりするので、ec2とdockerで合わせたいものです。

最終的に、オンプレに優しいansibleをdockerと組み合わせると、↓こんな感じでしょうか。オンプレもdockerも両方イケるぜ〜、な構成です。

環境 サーバ種別 OS プロビジョニング
ローカル docker or vagrant amazonlinux ansible
production ec2 amazonlinux ansible

こうしたいのですが、amazonlinuxのdocker imageは、ec2上のamazonlinuxと大分構成が異なり、単純にec2に適用していたplaybookをdockerに適用しても、エラーが出まくりで心が折れてしまいます。

今回はそのDockerfile周りのエラー祭りを何とかしていこうと思います。

目的

production環境はec2 + amazonlinux。

ローカル環境はdocker or vagrant + amazonlinuxとしたい。

どっちにもansibleのplaybookでプロビジョニングができるようにしたい。

環境

種別 バージョン
amazon linux 2017.09
ansible v2.4.0.0
docker v 17.09(docker for mac)

Dockerfileでエラーになるもの

グループ・ユーザ追加ができないんですけど・・・?

「よーし、まずはグループとユーザ追加するか〜」

RUN groupadd hoge

/bin/sh: groupadd: command not found

「!?」

いきなり洗礼を受けます。docker imageのamazonlinuxにはgroupadd, useraddコマンドありませんから〜!!

両コマンドを使えるようにするには、shadow-utilsをインストールします。

RUN yum install -y shadow-utils

sudoが無いんですけど・・・?

無いんだなこれが。

RUN yum install -y sudo

/etc/ssh/が無いんですけど・・・?

dockerへはsshしませんが、ec2のamazonlinuxにプロビジョニングする際に各種ssh関連ファイルが必要なので、用意しておく必要があります。

RUN yum install -y openssh-server

pipが無いんですけど・・・?

TASK [ansible : install ansible] ***********************************************************************************************************
fatal: [dev_server_1]: FAILED! => {"changed": false, "failed": true, "msg": "Unable to find any of pip2, pip to use.  pip needs to be installed."}

2手間必要になります。

RUN yum install -y python27-setuptools
RUN easy_install pip

これでPython2.7版のpipが使えるようになります。但しインストールパスの関係上sudoが必要になります。

pipのパスが通ってないんですけど・・・?

RUN ln -sf /usr/local/bin/pip /usr/bin/pip && \

作業ユーザでパス無しsudoしたいんですけど・・・?

RUN echo "hoge ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers.d/hoge

clockファイルが無いんですけど・・・?

ln: /etc/sysconfig/clock: No such file or directory

まーじか。

↓こうします。

RUN echo 'ZONE="Asia/Tokyo"' > /etc/sysconfig/clock && \
    rm -f /etc/localtime && \
    ln -fs /usr/share/zoneinfo/Asia/Tokyo /etc/localtime && \
    echo "LANG=\"en_US\"" > /etc/sysconfig/i18n

パス無し鍵認証の準備だけしたいんですけど・・・?

ec2のamazonlinuxの時と同様に鍵認証でsshできるようssh関連ファイル諸々を用意しておきます。

/etc/sshが無かったりsedで頑張ったり、ちょっと面倒臭いです。

ENV WORK_GROUP="hoge" \
    WORK_USER="fuga"

RUN groupadd ${WORK_GROUP} && \
    useradd -c "${WORK_USER} user" -d "/home/${WORK_USER}/" -g ${WORK_GROUP} -G ${WORK_GROUP},td-agent ${WORK_USER} && \
    mkdir -p /home/${WORK_USER}/.ssh && \
    chown ${WORK_USER}:${WORK_GROUP} /home/${WORK_USER}/.ssh && \
    chmod 700 /home/${WORK_USER}/.ssh && \
    sed -ri 's/#PermitRootLogin yes/PermitRootLogin no/g' /etc/ssh/sshd_config && \
    sed -ri 's/#PasswordAuthentication yes/PasswordAuthentication no/g' /etc/ssh/sshd_config

ADD ./docker.pem.pub /home/${WORK_USER}/.ssh/authorized_keys

RUN chown ${WORK_USER}:${WORK_GROUP} /home/${WORK_USER}/.ssh/authorized_keys && \
    chmod 600 /home/${WORK_USER}/.ssh/authorized_keys

FOREGROUND起動するものが無いんですけど・・・?

dockerは通常フォアグラウンドで起動し続けなければ、実行したコンテナは即座に終了してしまいますね。

そこで以下のように小細工をする事で、「無を無限にtailする」というちょっと哲学的な事をすると、無理矢理フォアグラウンド起動し、ansibleをぶつける事ができるようになります。

ENTRYPOINT tail -f /dev/null

ansibleは起動中のコンテナに対してしかプロビジョニングできないので、何とかしてフォアグラウンドで起動させ続ける必要があるのです。

ansibleのインベントリとplaybookのhostsどう書くの・・・?

まず前提として、Docker Connection Pluginを利用します。dockerでsshdを動かすのは何かと面倒なので、ssh関連ファイルがあるだけでsshしないコンテナを用意し、ansibleはconnection pluginで接続します。(Connection Pluginは恐らくdocker execしてるだけ)

さあ、これでコンテナはフォアグラウンドで起動し、playbookを叩く準備が整いました。

後は接続先を調整するのみです。

インベントリ
[local]
container_name
[all:children]
local
playbook
- hosts: local
  roles:
    - fabric

localの部分はどんな名前でもよくて、ホスト名はdockerのコンテナ名とします。dockerコンテナは起動中である必要があるので、前述したように、フォアグラウンドで起動し続けておく必要があります。

最後に、以下でplaybookを実行すれば、今までec2上のamazonlinuxに適用していたplaybookを、ローカルのdockerに適用する事ができます。

ansible-playbook \
    --connection=docker \
    -i inventory.ini \
    playbook.yml

connection節をplaybook側に書くという方法もありますが、いずれによ、右辺の部分は変数化しておき、環境によってconnection=local, connection=docker等と切り替える事ができるようにしておくといいと思います。

おまけ:Vagrantでamazonlinux!

docker imageには公式のイメージがありました。

vagrantはどうか?残念ながらありません。

但し、以下が配布されています。

app.vagrantup.com

AMIのバージョンが2017.03になっているので、自分で/etc/yum.confをいじってAMIのバージョンを2017.09等にすると、最新AMIのyum.repoを利用可能になります。

ただし、VBoxGuest周りが正しくインストールできていない?っぽく、vagrant upの/vagrantマウント時にエラーが出てしまいます。その状態でもvagrant ssh自体は可能です。