Dockerからの記事

序章

継続的インテグレーション(CI)は、開発者が コードをできるだけ頻繁に統合し、自動ビルドによって共有リポジトリにマージされる前後にすべてのコミットがテストされるプラクティスを指します

CIは開発プロセスをスピードアップし、本番環境での重大な問題のリスクを最小限に抑えますが、セットアップは簡単ではありません。 自動ビルドは、ランタイム依存関係のインストールと外部サービスの構成がローカルおよび開発環境とは異なる可能性がある別の環境で実行されます。

Docker は、環境標準化の問題を単純化して、アプリケーションのデプロイも標準化できるようにすることを目的としたコンテナー化プラットフォームです( Docker の詳細をご覧ください)。 開発者の場合、Dockerを使用すると、ローカルコンテナーでアプリケーションコンポーネントを実行することにより、ローカルマシンで本番環境をシミュレートできます。 これらのコンテナーは、アプリケーションや基盤となるOSに関係なく、 DockerComposeを使用して簡単に自動化できます。

このチュートリアルでは、Docker Composeを使用して、CIワークフローの自動化を示します。

Docker化された「Helloworld」タイプのPythonアプリケーションとBashテストスクリプトを作成します。 Pythonアプリケーションを実行するには、2つのコンテナーが必要です。1つはアプリ自体用で、もう1つはアプリの依存関係として必要なストレージ用のRedisコンテナーです。

次に、テストスクリプトが独自のコンテナーでDocker化され、テスト環境全体が docker-compose.test.yml ファイルに移動されるため、すべてのテスト実行が新鮮で統一された状態で実行されていることを確認できます。アプリケーション環境。

このアプローチは、アプリケーションをテストするたびに、依存関係を含め、アプリケーションに対して同一の新しいテスト環境を構築する方法を示しています。

したがって、テスト対象のアプリケーションや基盤となるインフラストラクチャとは関係なく、CIワークフローを自動化します。

要件

始める前に、次のものが必要になります。

  • Ubuntu14.04サーバー

  • sudo権限を持つroot以外のユーザー。 このチュートリアルに従って、これを設定できます

  • DockerおよびDockerComposeにある程度精通している。 このチュートリアル中にソフトウェアをインストールするため、リンクは参照用です

  • テスト、テスト、その他の(自動化された)テスト!テストしてCIを開発ワークフローに適用することの利点についてすでに確信しているはずです。

ステップ1—Dockerをインストールします

サーバーでDockerがまだ利用できない場合、最も簡単な方法は、公式のDockerインストールスクリプトをダウンロードして実行することです。このスクリプトは、sudoパスワードの入力を求めます(Docker のインストールの詳細については、こちらを参照してください)。

  1. wget -qO- https://get.docker.com/ | sh

Dockerの操作を簡単にするために、次のコマンドを使用してdockerグループにユーザーを追加します。

  1. sudo usermod -aG docker $(whoami)

ログアウトしてからサーバーにログインし、ユーザーのdockerグループをアクティブ化します。

ステップ2—DockerComposeをインストールします

Docker Composeは、宣言型アプローチを使用してマルチコンテナーアプリケーションを定義および実行するためのオープンソースツールです。 Docker Composeをインストールするには、次のコマンドを実行します。

  1. sudo apt-get update
  2. sudo apt-get -y install python-pip
  3. sudo pip install docker-compose

次のコマンドを実行して、docker-composeが正しくインストールされていることを確認します。

  1. docker-compose --version

次のように表示されます。

出力
docker-compose version 1.6.2, build 4d72027

これにより、インストールしたdocker-composeバージョンがわかります。

ステップ3—「HelloWorld」Pythonアプリケーションを作成する

このステップでは、このセットアップでテストできるアプリケーションの種類の例として、単純なPythonアプリケーションを作成します。

次のコマンドを実行して、アプリケーション用の新しいフォルダを作成します。

  1. cd ~
  2. mkdir hello_world
  3. cd hello_world

nanoを使用して新しいファイルapp.pyを編集します。

  1. nano app.py

次のコンテンツを追加します。

app.py
from flask import Flask
from redis import Redis

app = Flask(__name__)
redis = Redis(host="redis")

@app.route("/")
def hello():
    visits = redis.incr('counter')
    html = "<h3>Hello World!</h3>" \
           "<b>Visits:</b> {visits}" \
           "<br/>"
    return html.format(visits=visits)

if __name__ == "__main__":
    app.run(host="0.0.0.0", port=80)

app.pyは、Redisデータサービスに接続するFlaskに基づくWebアプリケーションです。 行visits = redis.incr('counter')は訪問数を増やし、この値をRedisに保持します。 最後に、訪問数を含むHello WorldメッセージがHTMLで返されます。

このアプリケーションには、FlaskRedisの2つの依存関係があり、最初の2行で確認できます。 これらの依存関係は、アプリケーションを実行する前に定義する必要があります。 新しいファイルを編集します。

  1. nano requirements.txt

内容を追加します。

Requirements.txt
Flask
Redis

ステップ4—「HelloWorld」アプリケーションをDocker化する

Dockerは、Dockerfileというファイルを使用して、特定のアプリケーションのDockerイメージを構築するために必要な手順を示します。 新しいファイルを編集します。

  1. nano Dockerfile

次の内容を追加します。

Dockerfile
FROM python:2.7

WORKDIR /app

ADD requirements.txt /app/requirements.txt
RUN pip install -r requirements.txt

ADD app.py /app/app.py

EXPOSE 80

CMD ["python", "app.py"]

各行の意味を分析してみましょう。

  • FROM python:2.7:「HelloWorld」アプリケーションイメージが公式のpython:2.7Dockerイメージから構築されていることを示します
  • WORKDIR /app:Dockerイメージ内の作業ディレクトリを/appに設定します
  • ADD requirements.txt /app/requirements.txt:ファイルrequirements.txtをDockerイメージに追加します
  • RUN pip install -r requirements.txt:アプリケーションpipの依存関係をインストールします
  • ADD app.py /app/app.py:アプリケーションのソースコードをDockerイメージに追加します
  • EXPOSE 80:アプリケーションがポート80(標準のパブリックWebポート)で到達できることを示します
  • CMD ["python", "app.py"]:アプリケーションを起動するコマンド

このDockerfileファイルには、「HelloWorld」アプリケーションのメインコンポーネントを構築するために必要なすべての情報が含まれています。

依存関係

次に、例のより洗練された部分に進みます。 このアプリケーションでは、外部サービスとしてRedisが必要です。 これは、従来のLinux環境では毎回同じ方法で設定するのが難しいタイプの依存関係ですが、Docker Composeを使用すると、毎回繰り返し可能な方法で設定できます。

docker-compose.ymlファイルを作成して、DockerComposeの使用を開始しましょう。

新しいファイルを編集します。

  1. nano docker-compose.yml

次の内容を追加します。

docker-compose.yml
web:
  build: .
  dockerfile: Dockerfile
  links:
    - redis
  ports:
    - "80:80"
redis:
  image: redis

このDockerComposeファイルは、「HelloWorld」アプリケーションを2つのDockerコンテナーでローカルに起動する方法を示しています。

webredisの2つのコンテナーを定義します。

  • webは、buildコンテキストの現在のフォルダーを使用し、作成したDockerfileファイルからPythonアプリケーションを構築します。 これは、Pythonアプリケーション専用に作成したローカルDockerイメージです。 redisコンテナIPにアクセスするために、redisコンテナへのリンクを定義します。 また、UbuntuサーバーのパブリックIPを使用してインターネットからポート80にパブリックアクセスできるようにします

  • redisは、redisという名前の標準のパブリックDockerイメージから実行されます

ステップ5—「HelloWorld」アプリケーションをデプロイする

このステップでは、アプリケーションをデプロイし、最終的にインターネット経由でアクセスできるようにします。 アプリケーションを何度も同じ方法でデプロイできるため、デプロイメントワークフローの目的では、これを開発環境、ステージング環境、または本番環境のいずれかと見なすことができます。

docker-compose.ymlおよびDockerfileファイルを使用すると、以下を実行してローカル環境の展開を自動化できます。

  1. docker-compose -f ~/hello_world/docker-compose.yml build
  2. docker-compose -f ~/hello_world/docker-compose.yml up -d

最初の行は、Dockerfileファイルからローカルアプリケーションイメージを構築します。 2行目は、docker-compose.ymlファイルで指定されているように、webおよびredisコンテナーをデーモンモード(-d)で実行します。

以下を実行して、アプリケーションコンテナが作成されていることを確認します。

  1. docker ps

これにより、helloworld_web_1およびhelloworld_redis_1という名前の2つの実行中のコンテナーが表示されます。

アプリケーションが起動していることを確認しましょう。 helloworld_web_1コンテナのIPは、次のコマンドを実行して取得できます。

  1. WEB_APP_IP=$(docker inspect --format '{{ .NetworkSettings.IPAddress }}' helloworld_web_1)
  2. echo $WEB_APP_IP

Webアプリケーションが適切なメッセージを返していることを確認します。

  1. curl http://${WEB_APP_IP}:80

これは次のようなものを返すはずです:

出力
<h3>Hello World!</h3><b>Visits:</b> 1<br/>

訪問数は、このエンドポイントに到達するたびに増加します。 UbuntuサーバーのパブリックIPアドレスにアクセスして、ブラウザーから「HelloWorld」アプリケーションにアクセスすることもできます。

独自のアプリケーションに合わせてカスタマイズする方法

独自のアプリケーションを設定するための鍵は、アプリを独自のDockerコンテナーに配置し、各依存関係を独自のコンテナーから実行することです。 次に、例に示すように、DockerComposeを使用してコンテナー間の関係を定義できます。 Docker Composeについては、このDockerComposeの記事で詳しく説明しています。

複数のコンテナーでアプリケーションを実行する方法の別の例については、DockerComposeWordPressとphpMyAdminを実行する方法に関するこの記事をお読みください。

ステップ6—テストスクリプトを作成する

次に、Pythonアプリケーションのテストスクリプトを作成します。 これは、アプリケーションのHTTP出力をチェックする単純なスクリプトになります。 スクリプトは、継続的インテグレーションデプロイメントプロセスの一部として実行する可能性のあるテストの種類の例です。

新しいファイルを編集します。

  1. nano test.sh

次の内容を追加します。

test.sh
sleep 5
if curl web | grep -q '<b>Visits:</b> '; then
  echo "Tests passed!"
  exit 0
else
  echo "Tests failed!"
  exit 1
fi

test.shは、「HelloWorld」アプリケーションの基本的なWeb接続をテストします。 cURLを使用して、訪問数を取得し、テストに合格したかどうかを報告します。

ステップ7—テスト環境を作成する

アプリケーションをテストするには、テスト環境をデプロイする必要があります。 また、ステップ5で作成したライブアプリケーション環境と同じであることを確認したいと思います。

まず、新しいDockerfileファイルを作成して、テストスクリプトをDocker化する必要があります。 新しいファイルを編集します。

  1. nano Dockerfile.test

次の内容を追加します。

Dockerfile.test
FROM ubuntu:trusty

RUN apt-get update && apt-get install -yq curl && apt-get clean

WORKDIR /app

ADD test.sh /app/test.sh

CMD ["bash", "test.sh"]

Dockerfile.testは、公式のubuntu:trustyイメージを拡張して、curl依存関係をインストールし、tests.shをイメージファイルシステムに追加し、CMDコマンドを示します。 Bashでテストスクリプトを実行します。

テストがDocker化されると、複製可能で不可知論的な方法で実行できます。

次のステップは、テストコンテナを「HelloWorld」アプリケーションにリンクすることです。 ここで、DockerComposeが再び助けになります。 新しいファイルを編集します。

  1. nano docker-compose.test.yml

次の内容を追加します。

docker-compose.test.yml
sut:
  build: .
  dockerfile: Dockerfile.test
  links:
    - web
web:
  build: .
  dockerfile: Dockerfile
  links:
    - redis
redis:
  image: redis

Docker Composeファイルの後半では、前のdocker-compose.ymlファイルと同じ方法で、メインのwebアプリケーションとそのredis依存関係をデプロイします。 これは、webおよびredisコンテナーを指定するファイルの一部です。 唯一の違いは、webコンテナがポート80を公開しなくなったため、テスト中にアプリケーションがパブリックインターネット経由で利用できなくなることです。 したがって、実際のデプロイとまったく同じ方法でアプリケーションとその依存関係を構築していることがわかります。

docker-compose.test.ymlファイルは、統合テストの実行を担当するsutコンテナー(テスト対象システムの名前)も定義します。 sutコンテナは、現在のディレクトリをbuildディレクトリとして指定し、Dockerfile.testファイルを指定します。 webコンテナにリンクしているため、アプリケーションコンテナのIPアドレスにtest.shスクリプトからアクセスできます。

独自のアプリケーションに合わせてカスタマイズする方法

docker-compose.test.ymlには、数十の外部サービスと複数のテストコンテナが含まれる場合があることに注意してください。 すべてのコンテナーが基盤となるOSを共有するため、Dockerはこれらすべての依存関係を単一のホストで実行できます。

アプリケーションで実行するテストがさらにある場合は、上記のDockerfile.testファイルのように、それらのテスト用に追加のDockerfileを作成できます。

次に、追加のDockerfileを参照して、docker-compose.test.ymlファイルのsutコンテナーの下に追加のコンテナーを追加できます。

ステップ8—「HelloWorld」アプリケーションをテストする

最後に、Dockerのアイデアをローカル環境からテスト環境に拡張すると、次のコマンドを実行して、Dockerを使用してアプリケーションをテストする自動化された方法が得られます。

  1. docker-compose -f ~/hello_world/docker-compose.test.yml -p ci build

このコマンドは、docker-compose.test.ymlに必要なローカルイメージを構築します。 -fを使用してdocker-compose.test.ymlを指し、-pを使用して特定のプロジェクト名を示していることに注意してください。

次に、以下を実行して、新しいテスト環境を起動します。

  1. docker-compose -f ~/hello_world/docker-compose.test.yml -p ci up -d

次のコマンドを実行して、sutコンテナの出力を確認します。

  1. docker logs -f ci_sut_1
出力
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100    42  100    42    0     0   3902      0 --:--:-- --:--:-- --:--:--  4200
Tests passed!

最後に、sutコンテナの終了コードをチェックして、テストに合格したかどうかを確認します。

  1. docker wait ci_sut_1
出力
0

このコマンドの実行後、テストに合格した場合、$?の値は0になります。 それ以外の場合、アプリケーションテストは失敗しました。

他のCIツールは、コードリポジトリのクローンを作成し、これらのいくつかのコマンドを実行して、実行時の依存関係や外部サービス構成を気にすることなく、アプリケーションの最新のビットでテストに合格しているかどうかを確認できます。

それでおしまい! 実稼働環境と同じ、新しく構築された環境でテストを正常に実行しました。

結論

DockerとDockerComposeのおかげで、アプリケーションの構築方法(Dockerfile)、ローカル環境のデプロイ方法(docker-compose.yml)、テストイメージの構築方法([ X186X]