kakts-log

programming について調べたことを整理していきます

Docker containerまとめ

概要

前記事に引き続き Docker公式ドキュメントのPart2の内容を整理

Part2 containers

Introduction

Dockerの方式でアプリをビルドしていく.
アプリケーションのヒエラルキーの下層部分であるコンテナから始めます.

コンテナの上層はserviceと呼ばれ、production環境でコンテナがどのように振る舞うのかを定義します. (Part3で取り上げる).
ヒエラルキーの最上層はスタックと呼ばれ、全てのserviceのやり取りを定義します.(Part5で取り上げる).
- Stack
- Services
- Container(このパートで取り上げる)

Your new develop environment

今まで,もしPythonアプリケーションを作る際に、まず最初にマシン上にPythonのランタイムをインストールしていました.
しかし,このやり方はマシンの環境が作成するアプリを期待通りに動作させる必要を生じさせた.

Dockerで、ユーザはイメージとして可搬性のあるPythonランタイムを利用できます.
これにより,ユーザが作成するビルドはアプリケーションコードと同様にPythonイメージも含むことができ,ランタイムと依存関係を全て保証できます.

Define a container with Dockerfile

Dockerfile はコンテナ内の環境で起こることを定義します.
ネットワーク・インタフェースへのアクセスと,ディスクドライブはこの環境内で仮想化され,システム内の他のものとは隔離されるため,ユーザは外部とやり取りするためにポートを指定し,どのファイルをコンテナ環境内にコピーするか指定します.
指定したあと,Dockerfileで定義されたアプリがどのような環境でも正常に振る舞うことを保証されます.

Dockerfile

新たなディレクトリにDockerfileを作成し,簡単なPythonアプリの環境を定義する.

# Use an official Python runtime as a parent image
FROM python: 2.7-slim

# Set the working directory to /app
WORKDIR /app

# Copy the current directory contents into the container at /app
Add . /app

# Install any needed packages specified in requirements.txt
RUN pip install --trusted-host pypi.python.org -r requirements.txt

# Make port 80 available to the world outside this containers
EXPORSE 80

# Define environment variable
ENV NAME world

# Run app.py when the container launches
CMD ["python", "app.py"]

Dockerfile内にまだ作成されていないapp.pyrequirements.txtがあるので作成していきます.

requirements.txt

Flask
Redis

app.py

from flask import Flask
from redis import Redis, RedisError
import os
import socket

# Connect to Redis
redis = Redis(host = "redis", db = 0, socket_connect_timeout = 2, socket_timeout = 2)

app = Flask(__name__)

@app.route("/")
def hello():
    try:
        visits = redis.incr("counter")
    except RedisError:
        visits = "<i>cannot connect to Redis, counter disbled</i?>"

    html = "<h3>Hello {name}!</h3>" \
           "<b>Hostname:</b> {hostname}<br/>" \
           "<b>Visits:</b> {visits}"
    return html.format(name=os.getenv("NAME", "world"), hostname=socket.gethostname(), visits=visits)

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

pip install -r requirements.txt によってFlaskとRedisライブラリをインストールし,アプリケーションでは環境変数のNAMEを表示させています.

これで一通りアプリケーションに必要なファイルが揃いました.
ディレクトリ配下に3つのファイルがある状態となります.

$ ls
Dockerfile      app.py          requirements.txt

Build the app

これでアプリケーションをビルドする準備が整いました.
Dockerfileが存在しているディレクトリ上で,docker build コマンドを実行してDockerイメージを作成します. -tオプションにより,イメージ名を指定できます.

docker build -t friendlyhello .

作成後,Dockerイメージが作られたかを確認します.

$ docker image ls
REPOSITORY                TAG                 IMAGE ID            CREATED              SIZE
friendlyhello             latest              596560250ed9        About a minute ago   148MB

Run the app

ここでdocker run コマンドによりアプリケーションを起動させていきます. -pオプションで,マシン上の4000番ポートをコンテナ内の80番ポートと紐付けた上で起動させます.

$ docker run -p 4000:80 friendlyhello
 * Running on http://0.0.0.0:80/ (Press CTRL+C to quit)

ここで,マシン上のwebブラウザから,localhostの4000番ポートにアクセスするとアプリケーションへアクセスできます.

-dオプションを使うことでバックグラウンドでも実行できます.

docker run -d -p 4000:80 friendlyhello

docker container ls または docker ps で,使用しているコンテナのIDなどの情報をみることができます. ポートのマッピング情報なども見れます.

$ docker ps
CONTAINER ID        IMAGE                     COMMAND                CREATED             STATUS              PORTS                     NAMES
c2ee894e48ab        friendlyhello             "python app.py"        5 seconds ago       Up 4 seconds        0.0.0.0:4000->80/tcp      nostalgic_perlman

起動したコンテナプロセスを止める場合 docker container stop で行えます.
この際に止めたいコンテナのコンテナIDを指定します.

$ docker container stop c2ee894e48ab
c2ee894e48ab

Share your image

作成したコンテナイメージの可搬性を実感するために,コンテナイメージを外部にアップロードしてみます.
これを行う際に必要なのは,コンテナをデプロイする際にレジストリにプッシュする方法を知ることのみです.

レジストリはレポジトリのコレクションであり,,レポジトリはイメージのコレクションです.
レジストリのアカウント毎に多くのレポジトリを作成できます.
dockerクライアントはデフォルトで,docker公式レジストリを使用します.

Log in with your Docker ID

https://cloud.docker.com/ でアカウントを作成したうえで,dockerコマンドを使ってマシン上でレジストリにログインします.

$ docker login

Tag the image

レジストリ内のレポジトリの表記は username/repository:tag となります.
タグは必須ではないですが, つけることを推奨します. なぜならタグはレジストリのDockerイメージのバージョンを表す仕組みになっているからです.

レポジトリとタグ名はコンテキストに合わせた名前をつけるべきです.

ここで,実際にDockerイメージにタグを付けてみます.
以下のような表記でタグを作成できます.
username repository TAGはそれぞれユーザによって変えてください.

docker tag image username/repository:TAG

作成したタグは docker image ls で確認できます.

$ docker image ls
REPOSITORY                TAG                 IMAGE ID            CREATED             SIZE
username/get-started         part2               16974e44583c        21 minutes ago      148MB

Publish the image

前項でDockerイメージに対するタグ付けができました.
ここで,タグをつけたDockerイメージをレポジトリにアップロードします.

docker push username/repository:TAG

アップロードしたイメージはパブリックに利用可能です.
Docker cloudにログインした上で下記のページで作成したイメージを確認できます.
https://hub.docker.com/

Pull and run the image from the remote repository

docker run コマンドでレポジトリとタグを直接指定してコンテナを起動することができます.

docker run -p 4000:80 username/repository:tag

もし指定したDockerイメージがローカルマシンに存在しない場合,DockerはレポジトリからDockerイメージをpullしてきます.