思い出とOutputと僕と

AWSで割とモダンな技術使う!!-2020/09/06 Qiita投稿記事

前置き

terraformで構成しようとしたが、まずはAWSを理解するためコンソールから構築 本記事は私自身が少し悩んだ、ネットワークの構成やトラブルシューティングについて重点的に記載されております。ハンズオン形式の記事はQiita等にも多くございますのでそちらを参照しつつ、こちらの記事でより理解を深めていただければな、と思います。

使用技術
Laravel6.x
AWS ECS(Fargate), RDS, ElasticCache
Docker, docker-compose

ネットワーク構成

VPCは10.1.0.0/16を利用。 サブネットの利用感は下記みたいな感じ

サブネット 用途
10.1.0.0/24, 10.1.1.0/24 Publicサブネット。LBに使うサブネット
10.1.2.0/24, 10.1.3.0/24 Privateサブネット。LBからECSに行くサブネット
10.1.4.0/24, 10.1.5.0/24 ECS~RDS間のサブネット。ECSからDBに接続するサブネット
10.1.6.0/24 EC2~RDS間のサブネット。EC2からDBに接続するサブネット

migrationはDockerfileには置かないのでDB接続用のEC2インスタンスを用意する。 (userのデータとかも取得できるので)

ルートテーブルでInternetGatewayと接続するのはLBとDB接続用のEC2インスタンスのみ。 appサーバーとDBサーバー(RDS)はローカルでしか接続できないように設定する。

※ネットワークの軽い知識があれば上記のサブネットや、CIDRを理解できます。 30分とかで理解できると思うのでYouTubeとかでおさらいしておいてください。

Fargateタイプにおいてのコンテナ間通信について

webコンテナはNginx(読み方はエンジンエックスっていうらしい、最近までエヌジンクスって読んでた)を利用していてappコンテナはPHPフレームワークLaravel。 そのためwebコンテナからappコンテナへの通信が必要。 ローカル内では下記のように.confファイルを記述する。 ポートはwebはHTTP通信のため80、appは9000。 (docker-compose.ymlで名前をそれぞれwebappで指定しておく)

01:server {
02:    listen 80;
03:    root /work/public;
04:    index index.php;
05:    charset utf-8;
06:
07:    location / {
08:        root /work/public;
09:        try_files $uri $uri/ /index.php$is_args$args;
10:    }
11:
12:    location ~ \.php$ {
13:        fastcgi_split_path_info ^(.+\.php)(/.+)$;
14:        fastcgi_pass app:9000;
15:        fastcgi_index index.php;
16:        include fastcgi_params;
17:        fastcgi_param SCRIPT_FILENAME /work/public/index.php;
18:        fastcgi_param PATH_INFO $fastcgi_path_info;
19:    }
20:}

上記のような設定だとAWS ECSのFargate起動タイプだとヘルスチェックで Taskが実行できません。 というエラーが出ます。そこで14行目を下記のように変更します。

14:        fastcgi_pass localhost:9000;

上記のようにする理由としては、Fargate起動タイプは同じローカルネットワーク内でtaskが実行されるためlocalhostは共有している。そのためコンテナ間通信はlocalhost:ポート番号で指定する。

トラブルシューティング

ヘルスチェックが通らない。

ECSを起動する際に、ヘルスチェックが通らず、taskが実行できなかったとき。 Dockerfileへの知見が甘かったため、 待つポート番号やコピーするディレクトリを間違えていたりした。 Dockerfileの最後の行にEXPOSE <ポート番号>を指定すること。 また、ローカルでコンテナを起動し期待するディレクトリにソースが入っているかを確認するといい。

ヘルスチェックは通るがLBのDNSに接続してもログインページが表示されない

ECS起動後にヘルスチェックが通るがログインページは表示されない場合。

ヘルスチェックは通っている
          ↓
ローカル内での通信はできている
          ↓
ネットワークの構成を確認し、落ちているところを確認

主に原因はネットワーク。 SGのインバウンドルールは適切か。ルートテーブルは適切か。再度確認する。 この過程が割と大事でCloudFomationとかで構成すると割と曖昧になりがちなネットワーク構成を理解できる。私の場合は、LBのターゲットグループを複数作成しており、利用したいターゲットグループの優先順位が一番ではなかったため、ログインページが表示されていなかった。

セッションの共有

可用性のために、複数のタスクを実行し、AutoScallingをオンにしていると思うので セッションの共有をしておかなければいけない。 Laravelのセッションはデフォルトでfileを選択しておりProject/storage/sessionsに保存されている。実行されるタスクが複数でセッションの保存先がfileの場合、それぞれのappコンテナの中に保存されてしまうので、セッションの共有をしなければいけない。 今回は、AWSのマネージドサービスであるElasticCacheを利用する。

※実装の工数上、現状(2020/09/06)では未構築のため後日追記する。 その際には上記のネットワーク構成にも修正を加える予定。

Dockerfileとdocker-compose.yml

いや、GitHub載せろよ。って思うよね。 僕的に、Qiita見ながらコピペできるのが理想なのでDockerfiledocker-compose.ymlはここに書きます。default.confは上記に記載済み。Fargate起動タイプの時はlocalhost指定してください。 ディレクトリ構成も載せておきます。

|
├── docker
|   |
│   ├── nginx
|   |   ├── Dockerfile
│   │   └── default.conf
│   └── php
│       ├── Dockerfile
│       └── php.ini
├── docker-compose.yml
|
├── .env
|
├── .gitignore
|
└── live
version: "3"
services:
  app:
    build:
      context: .
      dockerfile: ./docker/php/Dockerfile
      args:
        - TZ=${TZ}
    ports:
      - ${APP_PORT}:9000
    volumes:
      - ./live:/work
      - ./logs:/var/log/php
      - ./docker/php/php.ini:/usr/local/etc/php/php.ini
    working_dir: /work
    environment:
      # ここは要設定
      - DB_CONNECTION={DB_CONNECTION}
      - DB_HOST=${DB_HOST}
      - DB_DATABASE=${DB_DATABASE}
      - DB_USERNAME=${DB_USERNAME}
      - DB_PASSWORD=${DB_PASSWORD}
      - TZ=${TZ:-Asia/Tokyo}

  web:
    build:
      context: .
      dockerfile: ./docker/nginx/Dockerfile
    depends_on:
      - app
    ports:
      - ${WEB_PORT:-80}:80
    volumes:
      - ./live:/work
      - ./logs:/var/log/nginx
      - ./docker/nginx/default.conf:/etc/nginx/conf.d/default.conf
    environment:
      - TZ=${TZ:-Asia/Tokyo}

volumes:
  db-store:
FROM nginx:1.19-alpine

COPY ./docker/nginx/default.conf /etc/nginx/conf.d/default.conf

EXPOSE 80
FROM php:7.4-fpm-alpine

ARG PSYSH_DIR=/usr/local/share/psysh
ARG PHP_MANUAL_URL=http://psysh.org/manual/ja/php_manual.sqlite

ARG TZ

ENV COMPOSER_ALLOW_SUPERUSER 1
ENV COMPOSER_HOME /composer

RUN set -eux && \
  apk update && \
  apk add --update --no-cache --virtual=.build-dependencies \
    autoconf \
    gcc \
    g++ \
    make \
    tzdata && \
  apk add --update --no-cache \
    icu-dev \
    oniguruma-dev \
    libzip-dev && \
  cp /usr/share/zoneinfo/Asia/Tokyo /etc/localtime && \
  echo ${TZ} > /etc/timezone && \
  pecl install xdebug && \
  apk del .build-dependencies && \
  docker-php-ext-install intl pdo_mysql mbstring zip bcmath && \
  docker-php-ext-enable xdebug && \
  mkdir $PSYSH_DIR && wget $PHP_MANUAL_URL -P $PSYSH_DIR && \
  curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/bin --filename=composer && \
  composer config -g repos.packagist composer https://packagist.jp && \
  composer global require hirak/prestissimo

RUN apk add --no-cache freetype libpng libjpeg-turbo freetype-dev libpng-dev libjpeg-turbo-dev && \
  docker-php-ext-configure gd \
    --with-jpeg=/usr/include/ \
    --with-freetype=/usr/include/ && \
  NPROC=$(grep -c ^processor /proc/cpuinfo 2>/dev/null || 1) && \
  docker-php-ext-install -j${NPROC} gd && \
  apk del --no-cache freetype-dev libpng-dev libjpeg-turbo-dev


RUN chmod -R 777 /work/storage \
        /work/bootstrap/cache

RUN php artisan key:generate
RUN php artisan config:clear
RUN php artisan config:cache
# RUN php artisan migrate
# RUN php artisan db:seed

EXPOSE 9000

php.iniは自分で検索してください。笑 .envファイルがないと起動できないので各々の用途に合わせて記述してください。 一応下記に書いておきます。

TZ=Asia/Tokyo
APP_PORT=9000
DB_CONNECTION=mysql
DB_HOST=<RDSのエンドポイント>
DB_PORT=3306
DB_DATABASE=<DB名>
DB_USERNAME=<username, rootでもいい>
DB_PASSWORD=<セキュアなやつにしてね>

以上です。 まだ、CI/CDとかできていないので別記事にでも書こうと思っております。 AWS第一弾でした。 docker/php/Dockerfileは割と書きすぎてる気がするのでこれいらんよ、とかあったら教えて欲しいです。未熟者の記事ですが読んでいただいてありがとうございます。