kasei_sanのブログ

かせいさんのIT系のおぼえがきです。胡乱の方はnoteとtwitterへ

AWSのドキュメントに添ってECSを動かしてみた

この2つを参考に、ECSを動かしてみた

docs.aws.amazon.com

docs.aws.amazon.com

ゴール

Hello World と書かれた index.html を持つ apache サーバをECSで動作させて、ブラウザで動作確認する

手順

  1. DockerImageを作る
  2. DockerImageをECRに登録する
  3. Task DefinitionをECSに登録する
  4. Taskを実行するClusterを作成する
  5. Cluster上でTaskを起動する

DockerImageを作る

以下の Dockerfile を作成する

FROM ubuntu:12.04

# Install dependencies
RUN apt-get update -y
RUN apt-get install -y apache2

# Install apache and write hello world message
RUN echo "Hello World!" > /var/www/index.html

# Configure apache
RUN a2enmod rewrite
RUN chown -R www-data:www-data /var/www
ENV APACHE_RUN_USER www-data
ENV APACHE_RUN_GROUP www-data
ENV APACHE_LOG_DIR /var/log/apache2

EXPOSE 80

CMD ["/usr/sbin/apache2", "-D",  "FOREGROUND"]

Imageを作成

$ docker build -t hello-world .

動作確認

$ docker run -p 80:80 hello-world

DockerImageをECRに登録する

ECSから使用するImageを参照できるように、レジストリに登録する必要がある

リポジトリの作成

$ aws ecr create-repository --repository-name hello-world

戻り値

{
    "repository": {
        "repositoryUri": "${registryId}.dkr.ecr.us-east-1.amazonaws.com/hello-world",
        "repositoryName": "hello-world",
        "createdAt": 1521868901.0,
        "repositoryArn": "arn:aws:ecr:us-east-1:${registryId}:repository/hello-world",
        "registryId": "${registryId}"
    }
}

Imageにタグをつける

$ docker tag hello-world ${AWS_ACCOUNT_ID}.dkr.ecr.us-east-1.amazonaws.com/hello-world

タグとは

  • Gitのタグと近い概念
  • Imageに複数のタグが登録できる
  • 7.7 とか 7.7.4-alpine とかバージョンやディストリビューション毎にタグを付けて管理することが多い

上記のコマンドの場合、タグ名を指定していないので、latest タグが付く

タグ名を付けたい場合は、image名の後ろに :TAGNAME を付ける

ECRにImageをpushする

dockerコマンドからECRにログインするためのコマンドを生成させる

$ aws ecr get-login --no-include-email

標準出力に出てきたコマンドを実行して、ECRにログインする

  • ******** はパスワード
$ docker login -u AWS -p ******** https://${AWS_ACCOUNT_ID}.dkr.ecr.us-east-1.amazonaws.com

ECRにImageをpushする

$ docker push ${AWS_ACCOUNT_ID}.dkr.ecr.us-east-1.amazonaws.com/hello-world

Task DefinitionをECSに登録する

Task Definitionを作成

{
    "family": "hello-world",
    "containerDefinitions": [
        {
            "name": "hello-world",
            "image": "${AWS_ACCOUNT_ID}.dkr.ecr.us-east-1.amazonaws.com/hello-world",
            "cpu": 10,
            "memory": 500,
            "portMappings": [
                {
                    "containerPort": 80,
                    "hostPort": 80
                }
            ],
            "entryPoint": [
                "/usr/sbin/apache2",
                "-D",
                "FOREGROUND"
            ],
            "essential": true
        }
    ]
}

Task DefinitionをECSに登録する

$ aws ecs register-task-definition --cli-input-json file://hello-world-task-def.json

Taskを実行するClusterを作成する

AWSコンソールから作ると色々必要なものを自動で作ってくれるらしい

f:id:kasei_san:20180325174555p:plain

AWS Fargate でも良いが、まずはEC2インスタンスを使ったクラスタを理解したいので「EC2 Linux+ネットワーキング」を選択

f:id:kasei_san:20180325174719p:plain

必要な項目を入力後、Cluster、VPC、サブネット、IAMポリシー、オートスケーリンググループ等、必要なものが自動的に作成された

f:id:kasei_san:20180325175537p:plain

Cluster上でTaskを起動する

aws ecs run-task でタスクを起動できる

$ aws ecs run-task --task-definition hello-world --cluster test

AWSコンソールでTaskが起動していることを確認

f:id:kasei_san:20180325180307p:plain

インスタンスのURLにアクセスすると、Hello World が表示されている!

f:id:kasei_san:20180325180427p:plain

ひとまずここまで

今後理解したいこと

  • Service(今回はタスクしか使わなかった)
  • オートスケーリンググループ
  • ロードバランシング
    • 複数のコンテナで同じタスクを起動した場合、どのようにロードバランシングされるのか?
  • AWS Fargate

Amazon ECS 覚え書き

Amazon ECSとは

Amazon Elastic Container Service (Amazon ECS)

Docker コンテナをサポートする拡張性とパフォーマンスに優れたコンテナオーケストレーションサービスです

  • (最近乱立しがちでK8Sに統合が向かうのかどうなのかわからない)コンテナオーケストレーションサービスの一つ。
  • API/web画面から、EC2クラスタ上にDockerコンテナを起動/管理できる
  • AWS Fargate を使えば、インフラ(EC2)のことを考えずにコンテナを管理できる

用語

Task

1つ以上の協調して動作するコンテナ群

  • Dockerでは、1コンテナ1サービスを推奨しているので、何かを実現しようとすると大体複数のコンテナが必要になってくる

Task Definition

Taskの設定

  • docker-composeとかと近い概念

Service

  • タスクで必要なコンテナを指定した数だけ起動/維持してくれる
  • なんらかの理由でタスクが死んでも、サービスは必要数のタスクを維持する
  • あとELBとの連携とか

Cluster

Taskを実行するEC2の集合

  • 各EC2インスタンスには、ecs-agent なるサービスが起動していて、ECSとやり取りしている

参考

Amazon EC2 Container Service(ECS)のデータモデルについて整理した | Developers.IO

ruby:2.3.6-alpine3.4 に、postgresql-dev 9.6系をインストールしようとしたら conflict が発生した話

現象

alpine3.4 だと、postgresql-dev や client が 9.5 系

9.6 系を入れたくて、Dockerfileで /etc/apk/repositories を加工して、alpine3.5系のパッケージを入れるように変更した

/etc/apk/repositories

  http://dl-cdn.alpinelinux.org/alpine/v3.5/main
  http://dl-cdn.alpinelinux.org/alpine/v3.5/community

するとこんなエラーが

ERROR: unsatisfiable constraints:
  openssl-dev-1.0.2n-r0:
    conflicts: 
               libressl-dev-2.5.5-r0[pc:libcrypto=1.0.2n]
               libressl-dev-2.5.5-r0[pc:libssl=1.0.2n]
               libressl-dev-2.5.5-r0[pc:openssl=1.0.2n]
    satisfies: .ruby-rundeps-0[openssl-dev]
  libressl-dev-2.5.5-r0:
    conflicts: 
               openssl-dev-1.0.2n-r0[pc:libcrypto=2.5.5]
               openssl-dev-1.0.2n-r0[pc:libssl=2.5.5]
               openssl-dev-1.0.2n-r0[pc:openssl=2.5.5]
    satisfies: 
               postgresql-dev-9.6.8-r0[libressl-dev]
  build-dependencies-0:
    masked in: cache
    satisfies: world[build-dependencies]

ruby は OpenSSL を postgresql-dev は LibreSSL を使っているため、 複数のSSLLibraryが混在してconflictが発生している様子

原因

alpine linux が 3.5 になった時に、OpenSSL から LibreSSL に切り替わったのが原因 そのため、alpine3.4系に、3.5系のSSLを使うライブラリを入れるとConflictが発生する

alpinelinux.org

日本語の記事

gihyo.jp

対策

諦めた

springの子プロセスが `BUNDLE_APP_CONFIG` を無視するバグがある

現象

docker-compose を使って、run bin/rake を実行した時に、Could not find rake が発生

(ローカル環境では正しく動作する)

$ docker-compose exec web bundle exec bin/rake --version
Could not find rake-12.3.0 in any of the sources
Run `bundle install` to install missing gems.

発生したバージョン

ruby 2.5.0p0 (2017-12-25 revision 61468) [x86_64-linux-musl]
rake, version 12.3.0
Rails 5.1.4
gem 2.7.6
Bundler version 1.16.1

何故発生するのか?

ruby の docker image では 環境変数 BUNDLE_APP_CONFIG を設定している

  • 環境変数 BUNDLE_APP_CONFIG は、bundler の設定ファイルの場所を特定する環境変数
  • 未設定の場合は、./.bundle

以下のissueによると、springの子プロセスが bundler/setup を参照するときに、bundler が正しいconfigの場所を参照しなくなるとのこと

github.com

対策

  1. issue にあるように BUNDLE_APP_CONFIG を使わない
  2. springを使わない

docker-compose でよく使いそうなコマンドおぼえがき

ビルド

docker-compose build # Build or rebuild services

起動、停止

docker-compose up      # Create and start containers
docker-compose up -d   # デーモンとして起動

docker-compose start   # サービスを開始
docker-compose restart # サービスを再起動
docker-compose stop    # サービスをstop
docker-compose kill    # サービスを強制終了

コマンド実行

# 起動中のコンテナでコマンド実行
docker-compose exec ${service_name} ${command}

# コンテナを作成してコマンド実行(実行後コンテナを削除
docker-compose run --rm ${service_name} ${command} 

削除

# Stop and remove containers, networks
docker-compose down

# imageも削除
docker-compose down --rmi all

# 名前付きvolume も削除 
docker-compose rm  --volumes

一覧

docker-compose images               # image の一覧
docker-compose ps                   # 起動しているコンテナの一覧
docker-compose top ${service_name}  # サービスで実行中のプロセスの一覧
docker-compose logs ${service_name} # View output from containers

Alpine Linuxで素のRailsが動くDockerfile を作った

DBはPostgreSQLで、他に余分なgemを入れなければこんな感じ

FROM ruby:2.5.0-alpine

COPY Gemfile* /myapp/
WORKDIR /myapp

RUN apk upgrade --no-cache && \
    apk add --update --no-cache \
      postgresql-client \
      nodejs \
      tzdata && \
    apk add --update --no-cache --virtual=build-dependencies \
      build-base \
      curl-dev \
      linux-headers \
      libxml2-dev \
      libxslt-dev \
      postgresql-dev \
      ruby-dev \
      yaml-dev \
      zlib-dev && \
    gem install bundler && \
    bundle install -j4 && \
    apk del build-dependencies

COPY . /myapp

ポイント

  • --virtual を使うことで、bundle install にしか必要のないLibraryは、あとでまとめて削除してサイズを節約(100MBくらい違う)
  • gem install bundler は、ruby:2.5.0-alpine の中でもやっているけど、もっかい実行して最新のものを取得している

Alpine Linux とは?

組み込み用の超軽量ディストリビューション BusyBox をベースに、パッケージ管理ツール等をのせたものらしい

何が良いの?

Imageのサイズが軽い。とにかく軽い。単品のImageが5MBとか。

Imageが軽いと何が良いの?

生産性があがる

  • CIやデプロイ、開発環境作成時等、Imageをデプロイするタイミングでの待ち時間が減る
  • Imageのダウンロード/アップロードも待ち時間が減る

実際どのくらい違うの?

ruby 2.4.2 alpine と、ruby 2.4.2 でこれくらい違う

REPOSITORY            TAG                 IMAGE ID            CREATED             SIZE
ruby                  2.4.2-alpine        3bc1f3c1b02b        3 months ago        63.4MB
ruby                  2.4.2               5dce8a4be4f6        3 months ago        687MB

時代は alpine なの?

Docker公式のImageも Alpine Linuxだし割りとそんな感じ

ただ、コマンドも最低限だし、gemのインストールに必要なパッケージも色々手で入れる必要があるので、Dockerがあんまりわかんないうちは使わないほうが良いかも

おまけ

docker-compose.yml はこんな感じ

version: '3'
services:
  db:
    image: postgres:10-alpine
    volumes:
      - db_data:/var/lib/postgresql/data
  web:
    build: .
    command: bundle exec rails s -p 3000 -b '0.0.0.0'
    volumes:
      - .:/myapp:cached
      - bundle_data:/usr/local/bundle
    ports:
      - "3000:3000"
    depends_on:
      - db

volumes:
  db_data:
  bundle_data:

fluent-plugin-slack では、仕様上リンクテキストの修飾は使えないよというお話

先に結論

fluent-plugin-slack では、仕様上slack のテキストリンク修飾は使えないので諦める

(こんな風にそのまま出力される)

f:id:kasei_san:20180308220403p:plain

詳細

感想

もし修正するならば、オプション(unescapeとか)を追加して、エスケープの可否を設定するとかが良いのかな...