はじめに
オークファンでは多くのシステムを AWS で稼働しており、OS は特別な理由がない限り以下の理由で Amazon Linux 2 を選択しています。
- AWS が公式にサポートしている
- セキュリティアップデートやメンテナンスアップデートが継続的に提供される
- 追加料金なし
Amazon Linux 2 は RedHat ベースですが本家とは違っている部分もあるので、システム構築のための各種コマンドを試したくなる場面があります。そのたびにコスト管理をしてくれているインフラグループの顔色を伺いながら実際の AWS 環境に EC2 インスタンスを立ち上げるのも申し訳ないので、開発 PC の Docker 上に実際の EC2 と近い状態の Amazon Linux 2 を起動して動作検証を実施しています。
Docker イメージの作成
まずはベースとなる EC2 と近い状態の Docker イメージを作成します。
Amazon Linux 2 の Docker イメージは 公式の Docker Hub に公開されているのですが、まっさらな状態なので必要なものをインストールします。設定の大枠は以下となっています。
- 必要なパッケージをインストール
- SSH サーバを起動するように設定
-
ec2-user
を作成
具体的なディレクトリ構成はここでは以下とします。あとで SSH 接続するための公開鍵 (ここでは id_rsa.pub
としています) を Dockerfile
と同じ階層に配置しています。
amazonlinux2
├── Dockerfile
└── id_rsa.pub
Dockerfile
に以下を記述します。
# ベースイメージ
FROM amazonlinux:2
# 同一ディレクトリの公開鍵ファイルを Docker イメージの /tmp ディレクトリにコピーする
COPY ./id_rsa.pub /tmp/
# インストール済みのパッケージを最新版にアップデート
RUN yum -y update && \
# 追加で必要なパッケージをインストール
yum -y install \
sudo \
shadow-utils \
procps \
wget \
openssh-server \
openssh-clients \
which \
iproute \
e2fsprogs && \
# キャッシュを削除
yum clean all && \
# setuptools をインストール
wget https://bootstrap.pypa.io/ez_setup.py -O - | sudo python && \
# SSH サーバを起動
systemctl enable sshd.service && \
# パスワード認証による SSH アクセスを禁止
echo "PasswordAuthentication no" >> /etc/ssh/sshd_config && \
# ec2-user を追加
useradd ec2-user && \
# ec2-user で sudo コマンドを使用できるようにする
echo "ec2-user ALL=NOPASSWD: ALL" >> /etc/sudoers && \
# ec2-user のホームディレクトリ下に公開鍵を配置
sudo -u ec2-user mkdir -p /home/ec2-user/.ssh && \
mv /tmp/id_rsa.pub /home/ec2-user/.ssh/ && \
chmod -R go-rwx /home/ec2-user/.ssh && \
# 公開鍵を登録
cat /home/ec2-user/.ssh/id_rsa.pub >> /home/ec2-user/.ssh/authorized_keys && \
# ロケールを設定
echo "export LANG=en_US.UTF-8" >> /home/ec2-user/.bash_profile
他にも必要なパッケージがある場合は yum -y install
の部分に追加してください。ただし、あくまでも環境構築を検証するためのイメージなので、EC2 にデフォルトで入っていないものはここではインストールしないようにしています。
Docker イメージをビルドします。ここではタグ名を amazonlinux2-sshd
としています。
amazonlinux2
ディレクトリに移動して以下のコマンドを実行します。
$ docker build -t amazonlinux2-sshd .
ビルド完了後に docker images
コマンドで amazonlinux2-sshd
が作成されていることを確認してみてください。
正常にビルドができたことを確認できたら以下のコマンドで起動してみます。ここではコンテナ名を amazonlinux2-sshd-container
とし、22
番ポートに 2222
番ポートから接続できるようにしています。
ここで --privileged
を付加しないと SSH 接続が許可されないようです。さらに --rm
を付加して終了時にコンテナを削除するようにしていますが、削除しない場合はこのオプションを除外してください。
$ docker run --privileged --rm -d -p 2222:22 --name amazonlinux2-sshd-container amazonlinux2-sshd /sbin/init
起動したコンテナに SSH 接続してみます。普通に SSH 接続してもいいのですが、コンテナを作成するたびに信用するサーバを登録するのは面倒なので、無条件にサーバに接続するための alias コマンド ssh-igk
(他の別名でも OK) を登録してそちらで接続することにします。
こちらの作業はホスト OS 側で実施します。ホームディレクトリにある .bashrc
の末尾に alias
の行を追加します。
$ vi ~/.bashrc
# (前略)
alias ssh-igk='ssh -oUserKnownHostsFile=/dev/null -oStrictHostKeyChecking=no'
登録した alias を使用するために以下を実行しておきます。
$ source ~/.bashrc
登録した ssh-igk
コマンドを使用して ec2-user
で SSH ログインしてみます。
$ ssh-igk -i ~/.ssh/id_rsa ec2-user@localhost -p 2222
Warning: Permanently added '[localhost]:2222' (ECDSA) to the list of known hosts.
Last login: Wed Jul 3 12:21:43 2019 from gateway
[ec2-user@98a69d756c81 ~]$
警告のメッセージが出ますが問題なくログインできました。
以上で準備ができたので以下のコマンドでコンテナを停止しておきます。
$ docker stop amazonlinux2-sshd-container
システムを構築してみる
ベースとなる EC2 に近いイメージが作成できたので、こちらを使用してシステム構築を検証する環境を構築できます。ここでは sample-system
を作成する例を説明します。
ディレクトリ構成は以下とします。
(あらかじめ前述の amazonlinux2-sshd
をビルドしておく必要があります。)
sample-system
├── docker-compose.yml
├── sample-core-api
│ └── Dockerfile
└── sample-front-ui
└── Dockerfile
以下の要素でシステムが構成されている前提とします。
-
sample-front-ui
: フロント画面を提供するシステムを想定 -
sample-core-api
: データを提供する API システムを想定 -
sample-db
: 永続化のための RDB を想定 (実際の AWS 環境では RDS や Aurora など)
作成したそれぞれのファイルに以下を記述します。
sample-front-ui/Dockerfile
# あらかじめ amazonlinux2-sshd をビルドしておく必要があります
FROM amazonlinux2-sshd
# 以下はサンプルです
RUN amazon-linux-extras enable php7.3 && \
yum install -y php
sample-core-api/Dockerfile
# あらかじめ amazonlinux2-sshd をビルドしておく必要があります
FROM amazonlinux2-sshd
# 以下はサンプルです
RUN amazon-linux-extras install -y java-openjdk11
version: '3'
services:
# フロント画面を提供するシステムを想定
sample-front-ui:
build:
# sample-front-ui/Dockerfile のイメージを使用
context: ./sample-front-ui
container_name: sample-front-ui
restart: always
privileged: true
command: /sbin/init
ports:
# ホスト OS からの SSH ログイン用
- "2223:22"
# ホスト OS からの Web ページ動作確認用
- "8880:80"
networks:
samplenet:
ipv4_address: 172.20.0.10
# データを提供する API システムを想定
sample-core-api:
build:
# sample-core-api/Dockerfile のイメージを使用
context: ./sample-core-api
container_name: sample-core-api
restart: always
privileged: true
command: /sbin/init
ports:
# ホスト OS からの SSH ログイン用
- "2224:22"
# ホスト OS からの API 動作確認用
- "8881:8080"
networks:
samplenet:
# フロントシステムからの接続を想定
ipv4_address: 172.20.0.11
# 永続化のための RDB を想定
sample-db:
# その時点の Aurora で使用できる PostgreSQL のバージョンと合わせていたりします
image: postgres:10
container_name: sample-db
restart: always
environment:
POSTGRES_PASSWORD: changeit
ports:
# ホスト OS からの DB 接続用
- "5444:5432"
networks:
samplenet:
# API システムからの接続を想定
ipv4_address: 172.20.0.12
# ネットワーク設定
networks:
samplenet:
driver: bridge
ipam:
driver: default
config:
- subnet: 172.20.0.0/24
sample-system
ディレクトリに移動して以下のコマンドを実行します。
$ docker-compose up -d
イメージがビルドされていない場合はビルドが実行され、各システムが実行されます。
以下のコマンドで稼働状況を確認できます。
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
a4acb453f41a sample-system_sample-front-ui "/sbin/init" 2 minutes ago Up 2 minutes 0.0.0.0:2223->22/tcp, 0.0.0.0:8880->80/tcp sample-front-ui
acf6c2276129 sample-system_sample-core-api "/sbin/init" 2 minutes ago Up 2 minutes 0.0.0.0:2224->22/tcp, 0.0.0.0:8881->8080/tcp sample-core-api
6980309c6d57 postgres:10 "docker-entrypoint.s…" 2 minutes ago Up 2 minutes 0.0.0.0:5444->5432/tcp sample-db
フロントシステムに SSH ログインして環境構築作業を検証する場合は以下を実行します。
$ ssh-igk -i ~/.ssh/id_rsa ec2-user@localhost -p 2223
Warning: Permanently added '[localhost]:2223' (ECDSA) to the list of known hosts.
[ec2-user@a4acb453f41a ~]$
検証できたコマンドを sample-front-ui/Dockerfile
や sample-core-api/Dockerfile
などの RUN
に追記していけば最終的に開発 PC 上にシステム全体を自動構築することも可能です。
立ち上げたシステムをまとめて停止する場合は以下を実行してください。
$ docker-compose down --rmi all
上記では停止時にイメージをすべて削除するので、削除しない場合は --rmi all
の部分を除外してください。
おわりに
今回ご紹介した内容は Docker の一般的な使用方法とは少し異なるかと思います。一般的には 1 つのコンテナには 1 プロセスを実行させるように構成するので、Amazon Linux 2 にいろいろインストールするのではなく、PHP、Nginx、Java、PostgreSQL などをそれぞれの Docker イメージから起動していく方針となるはずです。あとそもそもコンテナに SSH ログインすることはあまりないと思います。
また、今後 AWS において EC2 を直接起動するのではなく Fargate、ECS、EKS を使用することが多くなりそうなので、今回のような EC2 を前提としたシステム構築を検証する頻度は減ってきそうです。
と、最後に記事を全否定ですがw 小さなシステムなどはまだ EC2 を使用して構築する場合もあるかと思いますのでその際はコストを気にすることなく動作検証をする方法の一つとして試してみてください。
最後に今回の手順はすべて Windows 10 Pro で実施していますが、Mac や Linux でも同様に実施できると思います。もしうまく動かない部分や記事に誤りなどありましたらご指摘ください。