AWSで学ぶコンテナの基礎 (1) Docker

コンテナといえば Docker です。Docker は別に怖くないし、Docker がないと何も始まらないです。

ここでは開発の準備と、Docker で簡単なイメージの作成を行っていきます。



目次

(0) はじめに
(1) Docker ← イマココ!
(2) イメージ自動生成
(3) サービス起動
(4) デプロイ
(5) Auto Scaling
(6) 費用と性能


開発準備

主に Git, Docker, Terraform を使って構築していきます。OS は Docker が動けば大丈夫なので、どのディストリビューションでもよいのですが、一応カーネル・バージョンに条件があるので、せっかくなのでわりと新し目の環境でやるとよいです。今回は、CentOS7.4 としてパッケージ関連を記述するので、各自変換する感じでお願いします。

進行図


手元にこれが揃えば大勝利だ!

Git

AWSの CodeCommit や GitHub を使うために必要です。てか、入ってるっしょ。


Terraform

AWSのリソース管理のために使います。管理画面ポチポチは最初の遊びだけにしましょう。Terraformでなくてもよいですが、どのようなリソースがどのように関連しているか、を理解しやすいので具体的なコードを記載していきます。


AWS CLI

別に必須じゃないですが、せっかくなので aws コマンドのインストールもしておきます。


Docker

コンテナを動かすのに Docker デーモンが動いている必要があります。標準パッケージは古く、現在は CE(コミュニティエディション)とEE(エンタープライズエディション)が提供されているので、Docker CE をインストールして動かしておきます。
  • Get Docker CE for CentOS | Docker Documentation
  • 豆ですが、データディレクトリ /var/lib/docker をそれなりに利用するので、別パーティションを利用したい場合は、



    Dockerで遊ぶ

    最初は Docker の詳しい仕組みはどうでもいいです。親OSの上で動く子OSがコンテナ、程度の認識で十分で、楽しくなってきたら他の仮想化技術との違いとか歴史を学びましょう。まずは、コンテナが動くことを確認します。

    コンテナを動かすには、まず元になるイメージが必要です。昔の仮想化技術を扱うときは、よく Linux のインストールイメージから起動して自分で作成したものですが、Docker には Docker Hub なる神サービスが存在していて、そこからスタートすることになります。


    Docker を扱う時に必ず重要なテーマとなる1つに、イメージサイズがあります。CentOS や Ubuntu を扱うと、どうしても最低サイズが数百MB 以上になるのですが、それだといざ本番稼働したときに、転送時間や転送量課金がボディブローのように響いてきます。そこで名乗りを上げるのが alpine です。

    一般的な Linux をインストールするときも、「最小構成で」みたいな選択がありますが、それよりも遥かな微小構成の alpine は、一桁MB からのスタートとなります。パッケージ管理が apk、シェルは /bin/busybox が基本となりますが、慣れの問題でありたいしたことではありません。開発システムを突き詰めていくと、もしかしたら実現できない事象にぶち当たる可能性はありますが、可能な限り最初から alpine で始めると、一味違うDocker使いになれるとか、なれないとか。


    これだと、イメージ取得しただけで、コンテナには何も触れていません。
    Docker の扱いには面白い特徴があり、

  • 起動処理の最後に、フォアグラウンドで動く何か がないとそのまま終了する
  • SSHで入って作業という従来のサーバー運用感覚は持ち込まない

  • というものがあります。とはいえ、Linux を扱うのにシェル作業がゼロというわけにはいかないので、中にお邪魔したい場合は……


    なぜ、このコマンドで作業できたかは、run –help でオプションの説明を確認し、inspect でイメージの設定を見れば理解できます。設定の Cmd という項目に /bin/sh と記述されており、上書き指定しない場合はこれが起動時に実行されるコマンドとなるからです。それを、-it によって持続処理とした形です。ちょっと楽しくなってきましたね。

    Dockerfileで独自イメージを作る

    Dockerもいろんな使い方があるんでしょうが、多くは任意の処理を何度も、もしくは並列で行わせるのが目的になると思います。定期的に同じジョブを実行するとか、並列でWEBサーバーを起動するとか、なんでもよいのですが、ここではWEBサーバーでいきましょう。

    Dockerfile という名前のファイルに、元イメージや任意の処理、最後に実行しておきたいデーモン、などをズラッと書くことで、自分の好きな処理をさせる独自イメージを作成することができます。そのイメージを、何かしらのコンテナ管理システムにブチ込むことで運用していく感じです。



    ベースイメージとアプリイメージを作成する

    アプリケーションを作成したあとの運用にて、さらなる開発とデプロイを何度も繰り返すことになりますが、1回あたりのデプロイやコンテナの起動速度は速いほど良いのは当然です。コンテナは処理の冪等性という安心感が強みですが、速度にも気を配ることで物理的な時間の短縮だけでなく、運用者の精神的な障壁を低くする効果があります。

    そのため、ここではいわゆるミドルウェア類の構築と、アプリケーションのデプロイを分けて構成していきます。デプロイしたいだけなのに毎回ミドルウェアのインストールを走らせる必要はないでしょう?そういった細かい工夫の積み重ねが、最終的なコンテナ運用の品質に大きく影響してくるっぽいですよ。

    ということで、2つのイメージをつくるコードはウチのGitHubから落としてきて、1つめの base イメージを作成し、それを元に2つめの application イメージをつくって動作確認までします。内容は簡素なもので、Nginx -> Ruby on Rails unicorn を動かすだけのものになっています。
  • GitHub : ベース用コード
  • GitHub : アプリ用コード

  • Dockerfile をザッと眺めると気になる点がいっぱいあると思います。その扱い方については最初のリンク集やググったりで調べてほしいところですが、最も重要なポイントの1つに軽量化があります。

    ディストリビューションが変わると方法は変わりますが、不要なものは残さない、という点で共通です。alpine の場合は、apk add の際に –no-cache をつけることでキャッシュしないようにし、またコンパイルのためだけに必要なパッケージなどは最後に削除しています。例えば ruby は rubyパッケージが無いと動かないけど、gem の mysql2 はインストールに mysql-dev が必要でも、その後は mysql-dev をアンインストールしても gem としては動作するでしょう。従来だと、パッケージはとりあえず入れておけばいい雰囲気があったりしましたが、容量削減には要不要の正しい把握が大切ということです。

    では次に、できたイメージを元にアプリ用イメージを作成します。


    最初のイメージと違って、Dockerfile の最後に ENTRYPOINT の entrypoint.sh があります。これは、先程も述べた、コンテナ継続のためにはフォアグラウンド実行が必要、というルールに従って書いたデーモン群です。Nginx は指定しなければ勝手にバックグラウンドにいき、unicorn はフォアグラウンドなのでこういう記述になっていますが、強制的にフォアグラウンドで終わらせるテクニックの1つとして tail -f /dev/null があるため、コメントアウトして記述しています。

    これで無事に2つのイメージができました。アプリケーションを更新したければ、2つめのコードを編集してビルドすればいいですし、ミドルウェアを更新したければ、1つめのコードを編集してビルドし、2つ目のイメージをそのままビルドすることになります。

    実際には、アプリケーションのコードは git clone してくるようなイメージになるので、Dockerfileの編集はそう発生するものではないでしょう。まぁそのへんは開発手法やインフラ構成によって変わるので、ここではこの超簡易イメージでいったんフィニッシュです。


    AWS ECR にイメージをプッシュしてみる

    最後のこの話は、最終的な構成からすると余談になるのですが、Dockerイメージを扱うならば知っておく必要があります。作成したイメージは、Registry に push (=アップロード) することができるので、AWS ECR で練習しておくとよいです。というのも、push 方法が docker コマンドを使う独特なものなので、どの Registry を扱うにせよ基本を知らないと困るからです。

    が、イメージ作成とアップロードは結局自動化するので、雑にコマンドベースで手順を書くだけにしておきます。


    進行図

    ここまでやりました。
    でもこの直接アップロードなんて作業は自動化により、すぐなくなります。




    Dockerの理解が進めば、もう勝ったも同然!

    次へまいります:イメージ自動生成