[02] Ansible 検証環境として使用できる Docker コンテナを構築する (コード列挙のみ)


|本シリーズのトップページ|
|:--|
|https://qiita.com/robozushi10/items/1790fdf5ba220b00a2a2|

## 概要

docker-compose を使って Ansible 検証環境として使用できる Docker コンテナを構築する.
このとき、Docker コンテナの中で systemctl の使用が可能になるようにしている.

なお、本記事は Dockerfile や docker-compose.yml 等の列挙であり、
セットアップ手順を見たい場合は、[[01]手順のみ](https://qiita.com/robozushi10/items/37ebfc92e54f1ded1a92) を参照すること.


## コンテナを作成したホスト

・ubuntu 18.04


## 今回構築する Ansible 検証用のコンテナ環境

### コンテナ構成 (2022/01/22 時点)

| 用途 | 台数 | OS | 備考 |
|:--|:--|:--|:--|
| Ansible Master | 1台 | Ubuntu 18.04 |■本コンテナに導入する Ansible バージョンは次の通り. <br/>・ansible = `3.4.0-1ppa~bionic` <br/>・ansible-base = `2.10.16-1ppa~bionic` <br/>■Slave に対して、アカウント「foo」であればパスワードなしで ssh 接続可能である.<br/>■必要ないはずだが、一応、アカウントのパスワードは Dockerfile に記している.|
| Ansible Slave | 8台 | Ubuntu 18.04 |■基となる Docker Image は上記 Master と同じである.(横着した)|


## コード全文

```bash
$ git clone https://github.com/robozushi10/qiita-ansible.git
```

## ファイル構成

```bash
.
|-- PV
|   |-- master
|   |   |-- .ssh ................... コンテナ内の /home/foo/.ssh/ に該当する
|   |   |   |-- config ............. SSH接続時の警告を無視するようにしている
|   |   |   |-- id_rsa ............. RSA 秘密鍵
|   |   |   |-- id_rsa.pub ......... RSA 公開鍵
|   |   |   `-- known_hosts
|   |   `-- share .................. 永続ボリューム. ここで実装していく
|   |-- slave01
|   |   |-- .ssh
|   |   |   `-- authorized_keys .... master の公開鍵 id_rsa.pub を登録済み
|   |   `-- share .................. 永続ボリューム. 
|   |-- slave02 〜 slave08 については slave01 と同じため省略する
略
|-- assets
|   `-- ubuntu1804
|       |-- Dockerfile ............. Master と Slave の両方で使用する Dockerfile
|       |-- foo .................... /etc/sudoers.d/foo として配置する (∵ sudo パスワード入力回避)
|       |-- setup-systemd.sh ....... コンテナ内で systemd を使うための設定処理をする
|       `-- ssh.service ............ /run/nologin を削除する処理を追記している
|
`-- docker-compose.yml
```


## コード

### assets/ubuntu1804/Dockerfile

<span stype="color:red">Github 上のコードは更新しているため、下記とは差分があります.</span>

```docker
FROM ubuntu:18.04

# ホストキーのチェックをしない(サーバなりすまし や MITM を疑わない)
ENV ANSIBLE_HOST_KEY_CHECKING False

# コンテナでの Proxy 設定を有効にする
# ENV http_proxy="http://proxy.co.jp:8080" \
#     https_proxy="http://proxy.co.jp:8080"
# COPY environment /etc/environment

# 必須パッケージと Ansible をインストールする
RUN apt-get update \
&&  apt-get install -y software-properties-common


# Ansible 3.x をインストールする
RUN add-apt-repository ppa:ansible/ansible-3 \
&&  apt-get update \
&&  apt-get install -y ansible

# 日本語化パッケージリストをインストール && localeを日本語設定に変更
RUN apt-get install -y language-pack-ja-base locales \
&&  locale-gen ja_JP.UTF-8
# 言語を日本語に設定
ENV LANG ja_JP.UTF-8

# アカウント「foo」、グループ「foo」を作成する
RUN groupadd -g 1000 foo \
&&  useradd -m -s /bin/bash -u 1000 -g 1000 foo
# foo アカウントのパスワードを foo として設定する
RUN echo 'foo:foo' | chpasswd
# さらに sudo 時にパスワード無しで実行できるようにする
COPY foo /etc/sudoers.d/foo

# systemd を使うための設定をしておく
RUN apt-get install -y init sudo systemd

COPY setup-systemd.sh /root
RUN bash /root/setup-systemd.sh

# sshd に加えて、その他必要と思われる最小限のツールをインストールしておく
RUN apt-get install -y openssh-server vim curl jq wget iputils-ping net-tools tree
# /run/nologin を削除するために sshd が起動したあとに
#「/lib/systemd/systemd-user-sessions start」を実行させるように
# 定義した /lib/systemd/system/ssh.service に差し替える
COPY ssh.service /lib/systemd/system/ssh.service

# root アカウントのパスワードを root とする
RUN echo 'root:root' | chpasswd

CMD ["/sbin/init"]

```

### docker-compose.yml

コンテナ内で systemd を使うために、次の🌟を定義している.


```yaml
version: '3'

services:
  master:
    build: ./assets/ubuntu1804/
    image:  myansiblemaster
    container_name: myansiblemaster
    tty: true
    volumes:
      - "/sys/fs/cgroup:/sys/fs/cgroup:ro" 🌟
      - "./PV/master/.ssh:/home/foo/.ssh"
      - "./PV/master/share:/share"
    cap_add:🌟
      - SYS_ADMIN🌟
    ports:
      - "49522-49999:22"
    privileged: true    🌟
    command: /sbin/init 🌟
    working_dir: /share
    logging:
      driver: json-file
      options:
        max-file: '4'
        max-size: 1m

  slave01:
    build: ./assets/ubuntu1804
    image:  myansibleslave
    container_name: myansibleslave01
    tty: true
    volumes:
      - "/sys/fs/cgroup:/sys/fs/cgroup:ro"
      - "./PV/slave01/.ssh:/home/foo/.ssh"
      - "./PV/slave01/share:/share"
    cap_add:
      - SYS_ADMIN
    ports:
      - "49522-49999:22"
    privileged: true    
    command: /sbin/init 
    working_dir: /share
    logging:
      driver: json-file
      options:
        max-file: '4'
        max-size: 1m
 
  slave02:
    build: ./assets/ubuntu1804
    image:  myansibleslave
    container_name: myansibleslave02
    tty: true
    volumes:
      - "/sys/fs/cgroup:/sys/fs/cgroup:ro"
      - "./PV/slave02/.ssh:/home/foo/.ssh"
      - "./PV/slave02/share:/share"
    cap_add:
      - SYS_ADMIN
    ports:
      - "49522-49999:22"
    privileged: true    
    command: /sbin/init 
    working_dir: /share
    logging:
      driver: json-file
      options:
        max-file: '4'
        max-size: 1m
 
  slave03:
    build: ./assets/ubuntu1804
    image:  myansibleslave
    container_name: myansibleslave03
    tty: true
    volumes:
      - "/sys/fs/cgroup:/sys/fs/cgroup:ro"
      - "./PV/slave03/.ssh:/home/foo/.ssh"
      - "./PV/slave03/share:/share"
    cap_add:
      - SYS_ADMIN
    ports:
      - "49522-49999:22"
    privileged: true    
    command: /sbin/init 
    working_dir: /share
    logging:
      driver: json-file
      options:
        max-file: '4'
        max-size: 1m
 
  slave04:
    build: ./assets/ubuntu1804
    image:  myansibleslave
    container_name: myansibleslave04
    tty: true
    volumes:
      - "/sys/fs/cgroup:/sys/fs/cgroup:ro"
      - "./PV/slave04/.ssh:/home/foo/.ssh"
      - "./PV/slave04/share:/share"
    cap_add:
      - SYS_ADMIN
    ports:
      - "49522-49999:22"
    privileged: true    
    command: /sbin/init 
    working_dir: /share
    logging:
      driver: json-file
      options:
        max-file: '4'
        max-size: 1m
 
  slave05:
    build: ./assets/ubuntu1804
    image:  myansibleslave
    container_name: myansibleslave05
    tty: true
    volumes:
      - "/sys/fs/cgroup:/sys/fs/cgroup:ro"
      - "./PV/slave05/.ssh:/home/foo/.ssh"
      - "./PV/slave05/share:/share"
    cap_add:
      - SYS_ADMIN
    ports:
      - "49522-49999:22"
    privileged: true    
    command: /sbin/init 
    working_dir: /share
    logging:
      driver: json-file
      options:
        max-file: '4'
        max-size: 1m
 
  slave06:
    build: ./assets/ubuntu1804
    image:  myansibleslave
    container_name: myansibleslave06
    tty: true
    volumes:
      - "/sys/fs/cgroup:/sys/fs/cgroup:ro"
      - "./PV/slave06/.ssh:/home/foo/.ssh"
      - "./PV/slave06/share:/share"
    cap_add:
      - SYS_ADMIN
    ports:
      - "49522-49999:22"
    privileged: true    
    command: /sbin/init 
    working_dir: /share
    logging:
      driver: json-file
      options:
        max-file: '4'
        max-size: 1m
 
  slave07:
    build: ./assets/ubuntu1804
    image:  myansibleslave
    container_name: myansibleslave07
    tty: true
    volumes:
      - "/sys/fs/cgroup:/sys/fs/cgroup:ro"
      - "./PV/slave07/.ssh:/home/foo/.ssh"
      - "./PV/slave07/share:/share"
    cap_add:
      - SYS_ADMIN
    ports:
      - "49522-49999:22"
    privileged: true    
    command: /sbin/init 
    working_dir: /share
    logging:
      driver: json-file
      options:
        max-file: '4'
        max-size: 1m
 
  slave08:
    build: ./assets/ubuntu1804
    image:  myansibleslave
    container_name: myansibleslave08
    tty: true
    volumes:
      - "/sys/fs/cgroup:/sys/fs/cgroup:ro"
      - "./PV/slave08/.ssh:/home/foo/.ssh"
      - "./PV/slave08/share:/share"
    cap_add:
      - SYS_ADMIN
    ports:
      - "49522-49999:22"
    privileged: true    
    command: /sbin/init 
    working_dir: /share
    logging:
      driver: json-file
      options:
        max-file: '4'
        max-size: 1m

```

### assets/ubuntu1804/setup-systemd.sh

```bash
#!/bin/bash
echo "dash dash/sh boolean false" | debconf-set-selections
DEBIAN_FRONTEND=noninteractive dpkg-reconfigure -p low dash

rm -f /etc/systemd/system/*.wants/*

cd /lib/systemd/system/sysinit.target.wants/
for i in *
do
 [ $i == systemd-tmpfiles-setup.service ] || rm -f $i
done

rm -f /lib/systemd/system/multi-user.target.wants/*
cd /lib/systemd/system/multi-user.target.wants/
ln -s ../dbus.service
rm -f /lib/systemd/system/local-fs.target.wants/*
rm -f /lib/systemd/system/sockets.target.wants/*udev*
rm -f /lib/systemd/system/sockets.target.wants/*initctl*
```

### assets/ubuntu1804/ssh.service

上記 Dockerfile および docker-compose.yml から立ち上げたコンテナでは
「systemd-user-sessions」が稼働していないため、/run/nologin が存在している.

その結果、アカウント「foo」による master から slave* への ssh 接続ができない状態になっている.

そこで /run/nologin を消すために、次の 🛑 処理を追記した.

```ini
[Unit]
Description=OpenBSD Secure Shell server
After=network.target auditd.service
ConditionPathExists=!/etc/ssh/sshd_not_to_be_run

[Service]
EnvironmentFile=-/etc/default/ssh
ExecStartPre=/usr/sbin/sshd -t
ExecStart=/usr/sbin/sshd -D $SSHD_OPTS
ExecStartPost=/lib/systemd/systemd-user-sessions start 🛑
ExecReload=/usr/sbin/sshd -t
ExecReload=/bin/kill -HUP $MAINPID
KillMode=process
Restart=on-failure
RestartPreventExitStatus=255
Type=notify
RuntimeDirectory=sshd
RuntimeDirectoryMode=0755

[Install]
WantedBy=multi-user.target
Alias=sshd.service
```

　

以上.