AWSのEC2にDockerをインストールして動かしてみたいと思ったことはありませんか?

本文書では、以下の手順で環境構築と動作確認を行います:

  1. Amazon Linux 2023がインストールされたEC2インスタンスにDockerをインストール
  2. Dockerを使用してWebサーバー(Apache)のコンテナを作成し、パブリックネットワークからのアクセスを確認
  3. Docker Composeをインストールし、PythonのWebフレームワークであるFastAPIの環境をDocker上に構築

この手順に従うことで、DockerとDocker Composeを使用した基本的なWeb環境の構築方法を学ぶことができます。

EC2インスタンスの作成

DockerをインストールするEC2インスタンスの作成を行います。 EC2のインスタンスの作成については下記の文書で公開済みなのでEC2インスタンスを作成した経験がない人は参考にしてください。

作成したEC2インスタンスにはEC2 instance Connectを利用して接続します。

Dockerの設定

Dockerのインストール

Dockerのインストールを行うためdnfコマンドを利用します。dnf -y updateコマンドでパッケージのアップデートを行っておきます。管理者権限が必要なのでコマンドの前にsudoをつけて実行しています。


$ sudo dnf -y update
Last metadata expiration check: 0:06:31 ago on Tue Feb 20 12:59:17 2024.
Dependencies resolved.
Nothing to do.
Complete!

dnf installコマンドを利用してdockerのインストールを行います。


$ sudo dnf install docker

インストールが完了するとdockerコマンドを利用することができるのでDockerのバージョンを確認しておきます。


[ec2-user@ip-172-31-3-114 ~]$ docker -v
Docker version 24.0.5, build ced0996
[ec2-user@ip-172-31-3-114 ~]$ which docker
/usr/bin/docker

Dockerの起動設定

コンテナの一覧を表示するためのdocker psコマンドを実行してもサービスが起動していないのでエラーとなります。


[ec2-user@ip-172-31-3-114 ~]$ docker ps
Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?

dockerのサービスが起動しているかどうかはsystemctl statusコマンドで確認することができます。


[ec2-user@ip-172-31-3-114 ~]$  sudo systemctl status docker.service
○ docker.service - Docker Application Container Engine
     Loaded: loaded (/usr/lib/systemd/system/docker.service; disabled; preset: disabled)
     Active: inactive (dead)
TriggeredBy: ○ docker.socket
       Docs: https://docs.docker.com

inactiveなのでsystemctl startコマンドでサービスを起動します。


[ec2-user@ip-172-31-3-114 ~]$ sudo systemctl start docker.service

再度ステータスを確認するとactiveになっていることが確認できます。


[ec2-user@ip-172-31-3-114 ~]$ sudo systemctl status docker.service
● docker.service - Docker Application Container Engine
     Loaded: loaded (/usr/lib/systemd/system/docker.service; disabled; preset: disabled)
     Active: active (running) since Tue 2024-02-20 13:21:52 UTC; 2s ago
TriggeredBy: ● docker.socket
       Docs: https://docs.docker.com
    Process: 27392 ExecStartPre=/bin/mkdir -p /run/docker (code=exited, status=0/SUCCESS)
    Process: 27393 ExecStartPre=/usr/libexec/docker/docker-setup-runtimes.sh (code=exited, status=0/SUCCESS)
   Main PID: 27395 (dockerd)
      Tasks: 8
     Memory: 35.3M
        CPU: 309ms
     CGroup: /system.slice/docker.service
             └─27395 /usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock --default-ulimit nofile=32768:65536

Feb 20 13:21:52 ip-172-31-3-114.ap-northeast-1.compute.internal systemd[1]: Starting docker.service - Docker Application Container Engine...
//略
Feb 20 13:21:52 ip-172-31-3-114.ap-northeast-1.compute.internal systemd[1]: Started docker.service - Docker Application Container Engine.

EC2を停止、起動(再起動)してもDockerサービスが起動するように自動起動設定を行います。設定する前はsystemctl is-enabledコマンドで確認することができます。


[ec2-user@ip-172-31-3-114 ~]$ sudo systemctl is-enabled docker.service
disabled

systemctl enableコマンドで自動起動を有効にしてis-enabledコマンドを実行するとdisabledからenabledに変わっていることが確認できます。


[ec2-user@ip-172-31-3-114 ~]$ sudo systemctl enable docker.service
Created symlink /etc/systemd/system/multi-user.target.wants/docker.service → /usr/lib/systemd/system/docker.service.
[ec2-user@ip-172-31-3-114 ~]$ sudo systemctl is-enabled docker.service
enabled

dockerサービスが起動したのでdocker psコマンドを実行すると先ほどのエラーとは異なりPermission deniedでコマンドが実行できないことがわかります。


[ec2-user@ip-172-31-3-114 ~]$ docker ps
permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock: Get "http://%2Fvar%2Frun%2Fdocker.sock/v1.24/containers/json": dial unix /var/run/docker.sock: connect: permission denied

dockerグループにec2-userを追加する必要があります。/etc/groupを確認するとdockerが追加されていることが確認できます。


[ec2-user@ip-172-31-3-114 ~]$ more /etc/docker
//略
ec2-user:x:1000:
docker:x:992:ec2-user

dockerグループへの追加はusermodコマンドで行います。


[ec2-user@ip-172-31-3-114 ~]$ sudo usermod -aG docker ec2-user

再度docker psコマンドを実行しても同じPermission Deniedのエラーが表示されます。一度インスタンスからログインして再ログインすると設定が反映されエラーは解消されます。docker psコマンドの実行結果は、コンテナは存在しないので下記の表示となります。


[ec2-user@ip-172-31-3-114 ~]$ docker ps
CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES

Apacheを利用した動作確認

設定したDockerが動作するのか確認するためにApacheのDockerイメージであるhttpdを利用してコンテナの起動を行います。ポートはEC2インスタンスを作成する際にセキュリティグループでhttpのポート80の接続を許可しているので80を指定しています。Dockerコンテナの名前はapache-testとしています。


$ docker run --name apache-test -d -p 80:80 httpd
Unable to find image 'httpd:latest' locally
latest: Pulling from library/httpd
e1caac4eb9d2: Pull complete 
87b0fe460fd9: Pull complete 
4f4fb700ef54: Pull complete 
9cebd3e3b523: Pull complete 
e9304da947c5: Pull complete 
b60d4b66b268: Pull complete 
Digest: sha256:104f07de17ee186c8f37b9f561e04fbfe4cf080d78c6e5f3802fd08fd118c3da
Status: Downloaded newer image for httpd:latest
f3101ca8efdea05c893cecfcf497778a5f2a27f823c93a174002b2bf0d6f7bcd

docker psコマンドを実行するとapache-testという名前のコンテナが起動していることが確認できます。


[ec2-user@ip-172-31-3-114 ~]$ docker ps
CONTAINER ID   IMAGE     COMMAND              CREATED         STATUS         PORTS                               NAMES
680d1e7206ee   httpd     "httpd-foreground"   5 seconds ago   Up 4 seconds   0.0.0.0:80->80/tcp, :::80->80/tcp   apache-test

ネット上から接続するためにはパブリック IPv4 DNSを利用します。パブリック IPv4 DNSはManagement Consoleのインスタンス概要画面で確認することができます。

ブラウザから”http://パブリック IPv4 DNS”をURLに設定して接続を行います。

ブラウザからのアクセス
ブラウザからのアクセス

ブラウザ上に”It works”が表示されれば設定した内容通りDocker上に起動しているApacheサーバからレスポンスが行われており、Dockerが正常に動作していることがわかります。

Docker Composeとは

Docker Composeは、複数のDockerコンテナを定義し実行するためのツールです。先ほどApacheで確認した通りdockerコマンドでは1つのコンテナを起動することができました。Docker Compserを利用するとdockerコマンドとは異なり、複数のコンテナを効率的に構成・管理できるため、特に複雑なアプリケーション環境では非常に便利です。

dockerコマンドの場合で複数のコンテナを起動したい場合は複数回コマンドを実行する必要があります。
fukidashi

Docker Composeのインストール

Docker ComposeはDockerとは別にインストールを行う必要があります。インストールではGithub上にあるファイルをcurlコマンドを利用してローカルにコピーを行います。インストール方法についてはドキュメントを参考に行います。

バージョンをv2.24.6を指定していますがこれは現時点の最新版を指定しているので実行する際はGitHubのreleasesページで最新版を確認してください。


[ec2-user@ip-172-31-3-114 ~]$ sudo curl -SL https://github.com/docker/compose/releases/download/v2.24.6/docker-compose-linux-x86_64 -o /usr/local/bin/docker-compose
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0
100 58.5M  100 58.5M    0     0  46.7M      0  0:00:01  0:00:01 --:--:--  118M

上記のコマンドではhttps://github.com/docker/compose/releases/download/v2.24.6/docker-compose-linux-x86_64にあるファイルを/usr/local/bin/docker-composeにコピーしているためsudoで実行しない場合に”Warning: Failed to open the file /usr/local/bin/docker-compose: Permission”のエラーとなります。

ファイルをコピーしただけでは権限が不足しているので実行権限を追加します。


[ec2-user@ip-172-31-3-114 ~]$ ls -l /usr/local/bin/docker-compose 
-rw-r--r--. 1 root root 61431093 Feb 21 00:34 /usr/local/bin/docker-compose
[ec2-user@ip-172-31-3-114 ~]$ sudo chmod +x /usr/local/bin/docker-compose
[ec2-user@ip-172-31-3-114 ~]$ ls -l /usr/local/bin/docker-compose 
-rwxr-xr-x. 1 root root 61431093 Feb 21 00:34 /usr/local/bin/docker-compose

実行権限を付与後はバージョンを確認するためにdocker-compose -vコマンドを実行します。実行時に指定したバージョンであることが確認できます。


[ec2-user@ip-172-31-3-114 ~]$ docker-compose -v
Docker Compose version v2.24.6

FastAPIの環境構築

Docker-composeのインストールが完了したのでPythonベースのWebフレームワークであるFastAPIの環境の構築をDocker-composeを利用して行います。

ec2-userのホームディレクトリにDockerfile, docker-compose.ymlファイルを作成します。それぞれには下記のコードを記述します。


FROM python

WORKDIR /usr/src/app

COPY /app/requirements.txt ./

RUN pip install --upgrade pip
RUN pip install -r requirements.txt

version: "3"
services:
  app:
    container_name: fastapi-dev
    build: .
    ports:
      - "80:8000"
    volumes:
      - ./app:/usr/src/app
    command: uvicorn main:app --reload --host 0.0.0.0

2つのファイルが作成できたらappディレクトリを作成してrequiments.txtを作成してインストールするPythonパッケージを記述します。


fastapi
uvicorn[standard]

FastAPIを動かすためのコードmain.pyファイルをappディレクトリの中に作成します。


[ec2-user@ip-172-31-3-114 app]$ more main.py
from fastapi import FastAPI

app = FastAPI()

@app.get("/")
def read_root():
    return {"Hello": "World"}

main.pyファイルの中のコードを以下のような意味を持っています。

  • “from fastapi import FastAPI”でFASTAPIライブラリからFastAPIをimportしてAPIアプリケーション(FastAPIのインスタンス)を作成しています。
  • @app.get(“/”)でルートのエンドポイントを設定しています。GETリクエストがルートURLにアクセスした時の処理をしてしています。
  • def read_root()はルートURLにリクエストが来た場合に実行する関数です。
  • JSONコードで{“Hello”: “World”}を戻しています。

作成したファイルをec2-userのホームディレクトリで実行します。コマンドは”docker-compose up -d”で”docker-compose up -d”を実行すると実行したディレクトリに存在するdocker-compose.ymlファイルが読み込まれ、その内容に基づいて処理が行われます。docker-compose.ymlファイルのbuildキーワードが指定されているので同じディレクトリにあるDockerfileを見つけてイメージをビルドします。


[ec2-user@ip-172-31-3-114 ~]$ docker-compose up -d
[+] Building 39.1s (10/10) FINISHED                                                                                                                                           docker:default
 => [app internal] load build definition from Dockerfile  
//略
[+] Running 1/2                                                                                                                                                                              
 ⠙ Network ec2-user_default  Created                                                                                                                                                    1.0s 
 ✔ Container fastapi-dev     Started

docker psコマンドを実行してfastapi-devという名前のコンテナが起動していることを確認します。


[ec2-user@ip-172-31-3-114 app]$ docker ps
CONTAINER ID   IMAGE          COMMAND                  CREATED          STATUS          PORTS                                   NAMES
ec45f2197266   ec2-user-app   "uvicorn main:app --…"   3 minutes ago   Up 3 minutes   0.0.0.0:80->8000/tcp, :::80->8000/tcp   fastapi-dev

apacheのコンテナを起動した時と同様にネット上から接続するためにはパブリック IPv4 DNSを利用します。パブリック IPv4 DNSはManagement Consoleのインスタンス概要画面で確認することができます。

ブラウザから”http://パブリック IPv4 DNS”をURLに設定して接続を行います。main.pyファイルで設定したJSONの{“Hello”:”World”}がブラウザ上に表示されれば Docker上で設定したFastAPIアプリは正常に動作しています。

起動しているFastAPIアプリへの接続
起動しているFastAPIアプリへの接続

EC2の再起動後にコンテナも起動させたい場合やdocker-compose.ymlファイルにrestart:alwaysを追加します。


version: "3"
services:
  app:
    container_name: fastapi-dev
    build: .
    restart: always
    ports:
      - "80:8000"
    volumes:
      - ./app:/usr/src/app
    command: uvicorn main:app --reload --host 0.0.0.0

自動起動が設定されているかどうかはdocker inspectコマンドのRestartPolicyのNameの値が”always”になっているかどうかで確認できます。設定されていない場合はNameの値は何も設定されていません。

EC2へのDocker, Docker Composeのインストールの方法とインストールしたDockerを利用してApache, FastAPIが動作することを確認することができました。