コンテナイメージの構築方法に重点を置いたコンテナ化の概念

この記事では、**コンテナ化**について紹介し、**Docker**と**Docker Compose**を使ってコンテナイメージを構築する方法を紹介します。

 [Alibaba Cloud Community Blog](https://www.alibabacloud.com/blog?spm=a2c65.11461447.0.0.56fb6c65ft0HZI) Alex著

アプリケーションコンテナ化の概念では、同じオペレーティングシステム上でアプリケーションインスタンスを分離する必要があります。アプリケーションがオペレーティングシステム（OS）のカーネルを共有しているため、仮想マシンとは異なります。コンテナは、異なるオペレーティングシステムや、ベアメタル、仮想プライベートサーバー（VPS）、クラウドプラットフォームなどの多様なインフラストラクチャで動作します。

コンテナには、隔離されたソフトウェアインスタンスの実行を可能にするファイル、環境、プラグイン、およびライブラリが含まれます。これらのコンポーネントをまとめて、カーネル上で独立して実行可能なイメージを構成します。イメージはホスト上に展開され、複数のコンテナが同じリソース上で動作するため、仮想マシンよりも効率的です。Dockerは現在最も人気のあるコンテナ化ツールの一つであり、RKTコンテナエンジンも同様に有名です。この2つの技術は、それぞれユニバーサルランタイム（runC）とアプリコンテナ（appc）をベースにしています。また、Docker Engineは、ほとんどのOSで利用できるオープンソースのコンテナ化技術です。コンテナ化に関わると、Dockerにたどり着くことがあります。ベンダー固有のツールもありますが、ほとんどの組織はユーザーベースの大きいポータブルなオープンソースツールを選択します。

下の画像は、そのアーキテクチャを示しています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/647921/bcc55a1a-590b-6ead-efe0-5a1eced8a31b.png)

ソース： Nexinto

開発者としては、Dockerイメージに新しいコードを導入し、信頼性の高い一貫した方法でイメージを作成したいと思うかもしれません。[Dockerfile]()は、Dockerイメージを作成するための宣言的で一貫性のある方法を提供します。さらに、複数の異質なコンテナをコンテナ化したい場合もあるでしょう。このチュートリアルでは、コンテナ化の基本、DockerfileからのDockerイメージの構築、コンテナネットワーキングについてウォークスルーで説明します。

このチュートリアルでは、以下のものが必要です。

- Ubuntu 16.04を実行するAlibaba Cloud ECS
- Dockerコミュニティ・エディション

#DockerfilesとDockerイメージ
`Dockerfiles`は、コマンドのリストを含むシンプルなテキストベースのファイルで、Dockerコマンドラインを使用してそのようなコマンドを実行すると、特定のイメージが作成されます。

`Docker build`コマンドは、イメージ作成に必要な指定されたソフトウェアのバージョンを評価します。Dockerfileはルートディレクトリではなく、独自のディレクトリに置くことに注意してください。

Dockerfileコマンド

様々なDockerfileコマンドのリストを簡単に見てみましょう。

- ADD: ファイルをあるソースからコンテナのファイルシステムにコピーする
- CMD: 指定したコンテナ内でコマンドを実行する
- WORKDIR: CMDコマンドのパスを指定する
- FROM: ビルドのベースイメージを定義
- ENV: 環境変数を指定する
- USER: コンテナが実行されるユーザーを表す
- ENTRYPOINT: 実行可能ファイルとして実行されるコンテナを構成する
- RUN：コマンドを実行する
- EXPOSE：外部からアクセス可能なアドレスを介してコンテナのネットワークを可能にするポートを作成する
- MAINTAINER：イメージ作成者の詳細を管理する
- VOLUME：コンテナにホストストレージへのアクセスを提供する

**Dockerfileからイメージを作成する**

では、Dockerfileを作成し、Dockerイメージをビルドしてみましょう。

```
mkdir dockerfiles
cd dockerfiles
```

この記事では、[サンプルのDockerfile](https://github.com/docker-library/mysql/blob/696fc899126ae00771b5d87bdadae836e704ae7d/5.5/Dockerfile?spm=a2c65.11461447.0.0.56fb6c65ft0HZI)を使用します。

まず、以下のようなファイルを作成します。

```
sudo nano mysql
```

次に、以下のテキストをファイルに貼り付けて保存します。



```
FROM debian:stretch-slim
    

    # add our user and group first to make sure their IDs get assigned consistently, regardless of whatever dependencies get added
    RUN groupadd -r mysql && useradd -r -g mysql mysql
    

    RUN apt-get update && apt-get install -y --no-install-recommends gnupg dirmngr && rm -rf /var/lib/apt/lists/*
    

    # add gosu for easy step-down from root
    ENV GOSU_VERSION 1.7
    RUN set -x \
        && apt-get update && apt-get install -y --no-install-recommends ca-certificates wget && rm -rf /var/lib/apt/lists/* \
        && wget -O /usr/local/bin/gosu "https://github.com/tianon/gosu/releases/download/$GOSU_VERSION/gosu-$(dpkg --print-architecture)" \
        && wget -O /usr/local/bin/gosu.asc "https://github.com/tianon/gosu/releases/download/$GOSU_VERSION/gosu-$(dpkg --print-architecture).asc" \
        && export GNUPGHOME="$(mktemp -d)" \
        && gpg --batch --keyserver ha.pool.sks-keyservers.net --recv-keys B42F6819007F00F88E364FD4036A9C25BF357DD4 \
        && gpg --batch --verify /usr/local/bin/gosu.asc /usr/local/bin/gosu \
        && gpgconf --kill all \
        && rm -rf "$GNUPGHOME" /usr/local/bin/gosu.asc \
        && chmod +x /usr/local/bin/gosu \
        && gosu nobody true \
        && apt-get purge -y --auto-remove ca-certificates wget
    

    RUN mkdir /docker-entrypoint-initdb.d
    

    RUN apt-get update && apt-get install -y --no-install-recommends \
    # for MYSQL_RANDOM_ROOT_PASSWORD
            pwgen \
    # FATAL ERROR: please install the following Perl modules before executing /usr/local/mysql/scripts/mysql_install_db:
    # File::Basename
    # File::Copy
    # Sys::Hostname
    # Data::Dumper
            perl \
    # mysqld: error while loading shared libraries: libaio.so.1: cannot open shared object file: No such file or directory
            libaio1 \
    # mysql: error while loading shared libraries: libncurses.so.5: cannot open shared object file: No such file or directory
            libncurses5 \
        && rm -rf /var/lib/apt/lists/*
    

    ENV MYSQL_MAJOR 5.5
    ENV MYSQL_VERSION 5.5.62
    

    RUN apt-get update && apt-get install -y ca-certificates wget --no-install-recommends && rm -rf /var/lib/apt/lists/* \
        && wget "https://cdn.mysql.com/Downloads/MySQL-$MYSQL_MAJOR/mysql-$MYSQL_VERSION-linux-glibc2.12-x86_64.tar.gz" -O mysql.tar.gz \
        && wget "https://cdn.mysql.com/Downloads/MySQL-$MYSQL_MAJOR/mysql-$MYSQL_VERSION-linux-glibc2.12-x86_64.tar.gz.asc" -O mysql.tar.gz.asc \
        && apt-get purge -y --auto-remove ca-certificates wget \
        && export GNUPGHOME="$(mktemp -d)" \
    # gpg: key 5072E1F5: public key "MySQL Release Engineering <mysql-build@oss.oracle.com>" imported
        && gpg --batch --keyserver ha.pool.sks-keyservers.net --recv-keys A4A9406876FCBD3C456770C88C718D3B5072E1F5 \
        && gpg --batch --verify mysql.tar.gz.asc mysql.tar.gz \
        && gpgconf --kill all \
        && rm -rf "$GNUPGHOME" mysql.tar.gz.asc \
        && mkdir /usr/local/mysql \
        && tar -xzf mysql.tar.gz -C /usr/local/mysql --strip-components=1 \
        && rm mysql.tar.gz \
        && rm -rf /usr/local/mysql/mysql-test /usr/local/mysql/sql-bench \
        && rm -rf /usr/local/mysql/bin/*-debug /usr/local/mysql/bin/*_embedded \
        && find /usr/local/mysql -type f -name "*.a" -delete \
        && apt-get update && apt-get install -y binutils && rm -rf /var/lib/apt/lists/* \
        && { find /usr/local/mysql -type f -executable -exec strip --strip-all '{}' + || true; } \
        && apt-get purge -y --auto-remove binutils
    ENV PATH $PATH:/usr/local/mysql/bin:/usr/local/mysql/scripts
    

    # replicate some of the way the APT package configuration works
    # this is only for 5.5 since it doesn't have an APT repo, and will go away when 5.5 does
    RUN mkdir -p /etc/mysql/conf.d \
        && { \
            echo '[mysqld]'; \
            echo 'skip-host-cache'; \
            echo 'skip-name-resolve'; \
            echo 'datadir = /var/lib/mysql'; \
            echo '!includedir /etc/mysql/conf.d/'; \
        } > /etc/mysql/my.cnf
    

    RUN mkdir -p /var/lib/mysql /var/run/mysqld \
        && chown -R mysql:mysql /var/lib/mysql /var/run/mysqld \
    # ensure that /var/run/mysqld (used for socket and lock files) is writable regardless of the UID our mysqld instance ends up having at runtime
        && chmod 777 /var/run/mysqld
    

    VOLUME /var/lib/mysql
    

    COPY docker-entrypoint.sh /usr/local/bin/
    RUN ln -s usr/local/bin/docker-entrypoint.sh /entrypoint.sh # backwards compat
    ENTRYPOINT ["docker-entrypoint.sh"]
    

    EXPOSE 3306
    CMD ["mysqld"]
```

以下のコマンドを実行して、Dockerfileへのパスを確立します。

```
pwd
```

Dockerfileのあるディレクトリ内で以下のコマンドを実行します。

```
docker build -t IMAGE_NAME .
```

イメージの名前が適切に変更されていることを確認してください。ここまでで、1つのコンテナを構築する方法がわかりました。しかし、これは非常に基本的な概念であり、事前のユースケースには十分ではありません。次のセクションでは、このコンセプトをさらに発展させるDocker Composeを紹介します。



#Docker Compose
Docker Composeは、複数のコンテナを使ったアプリケーションの作成と実行に役立ちます。Docker Composeを使用するには、以下の手順に従ってください。

- アプリの環境変数を定義した`Dockerfile`を作成する。
- アプリのサービス変数を定義した`docker-compose.yml`ファイルを作成する。
- `docker-compose up`を実行して、アプリケーションを実行する。

ここから先は、Docker Composeファイルの使用方法について説明します。ここでは、`docker-compose.yml`ファイルのサンプルを紹介します。

```
version: "2"
 services:
redis-master: 
image: redis:latest 
ports:
- "6379"
redis-slave: 
image: gcr.io/google_samples/gb-redisslave:v1 
ports: 
- "6379" 
environment: - GET_HOSTS_FROM=dns
frontend: 
image: gcr.io/google-samples/gb-frontend:v3 
ports: 
- "80:80" 
environment: 
- GET_HOSTS_FROM=dns
```

Docker Composeファイルは、可能な限り再利用するためにコンテナを作成するための設定を保持しています。さらに、環境を分離しながらデータの整合性を確保するために、必要に応じて固有のビルド番号を使用して、ボリュームを維持したり、新しいコンテナに再割り当てしたりします。

#Dockerネットワーキング
Dockerのネットワーキング設定は、セキュリティのためのコンテナの分離を可能にします。デフォルトでは、Dockerはインストール時に`bridge`、`none`、および`ホストネットワーク`をインストールします。コンテナは、`—net`フラグを使って指定された場合、インストールされたネットワークのいずれかを使用することができます。

必要に応じてさらに多くのネットワークを作成し、コンテナを割り当てることができます。また、ネットワークは、コンテナが必要なすべてのネットワークに接続されている限り、ネットワーク内およびネットワーク間でのコンテナの通信を促進します。

以下のコマンドを実行して、新しいネットワークを作成します。

```
sudo docker network create sample_net
```

以下のコマンドを実行すると、利用可能なネットワークの一覧が表示されます。

```
docker network ls
```

出力には、以下のようなネットワークの一覧が表示されます。

```
NETWORK ID          NAME                DRIVER              SCOPE
7bb95b5aba4f        bridge              bridge              local
d3e1851dfab4        host                host                local
71ef04fce6c4        none                null                local
cef39ad3d250        sample_net          bridge              local
```

コンテナをネットワークに割り当てるには、以下のコマンドを実行します。

```
docker run container --net=sample_net
```

ネットワークに接続されているコンテナを以下のコマンドで検査します。

```
docker inspect <network_name>
```

それでは、3種類のネットワークについて説明します。

###ホストモードのネットワーキング
Dockerのホストモードネットワーキングは、コンテナがホストIPを継承するため、パブリックネットワーク上にコンテナを公開することができます。

以下のファイルを参照してください。

```
docker run -d --net=host ubuntu:18.04 tail -f /dev/null
ip addr | grep -A 2 eth0:
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9001 qdisc mq state UP group default qlen 1000
    link/ether 06:58:2b:07:d5:f3 brd ff:ff:ff:ff:ff:ff
    inet **192.168.7.10**/22 brd 192.168.100.10 scope global dynamic eth0

docker ps
CONTAINER ID  IMAGE         COMMAND  CREATED
STATUS        PORTS         NAMES
dj33dd5d9023  ubuntu:18.04  tail -f  2 seconds ago
Up 2 seconds                jovial_blackwell
docker exec -it dj33dd5d9023 ip addr
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9001 qdisc mq state UP group default qlen 1000
    link/ether 06:58:2b:07:d5:f3 brd ff:ff:ff:ff:ff:ff
    inet **192.168.7.10**/22 brd 192.168.100.10 scope global dynamic eth0
```

###コンテナモードのネットワーキング
コンテナのネットワーキングはDockerのデフォルトモードだが、Kubernetesとの親和性が高いコンテナのネットワークスタックをカスタマイズすることもできます。前述したように、コンテナを同じネットワークに接続することが可能です。以下のコードを参照してください。

```
docker run -d -P --net=bridge nginx:1.9.1

docker run -it --net=container:admiring_engelbart ubuntu:14.04 ip addr
...
8: eth0@if9: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9001 qdisc noqueue state UP group default
    link/ether 02:42:ac:11:00:03 brd ff:ff:ff:ff:ff:ff
    inet **172.17.0.3**/16 scope global eth0
```

###ネットワークをオフに
Dockerのno-networkingモードでは、ネットワークをオフにすることができます。このシナリオでは、コンテナはそれぞれのネットワークに配置されますが、何の設定もされていないため、以下のように無効化されます。

```
docker run -d -P --net=none nginx:1.9.1
docker ps
CONTAINER ID  IMAGE          COMMAND   CREATED
STATUS        PORTS          NAMES
h7c55d90563f  nginx:1.9.1    nginx -g  2 minutes ago
Up 2 minutes                 grave_perlman
docker inspect h7c55d90563f | grep IPAddress
    "IPAddress": "",
    "SecondaryIPAddresses": null,
```

#サービスインスタンスのスケール
前のセクションでは、Docker Composeの設定について説明しました。ここでは、`docker-compose.ymlfile`に定義されたサービスをスケールする方法を見てみましょう。

```
docker-compose scale <service name> = <no of instances>
```

上記のcomposeファイルに対して、以下のいずれかのコマンドを実行します。

```
docker-compose scale redis-master=4
```

または

```
docker-compose up -scale redis-master=4 -d
```

以下のコマンドを実行して、サービスにポートの範囲を割り当てます。


```
services: 
redis-master: 
image: redis:latest 
ports: - "6379-6385:6379"
```

これで、`docker-compose.yml`ファイルで定義したサービスのスケールアップに成功します。

#まとめ
このチュートリアルでは、コンテナイメージを構築する2つの方法（DockerfilesとDocker Compose）に重点を置いて、コンテナ化の概念を探りました。Kubernetesは、主にマイクロサービスや分散型アプリケーションのためのコンテナ化と密接に連携しています。マイクロサービスアーキテクチャでは、APIが異なるサービスの通信を可能にし、コンテナ層が負荷分散を行います。Kubernetesには、相互に通信するポッドがあり、マイクロサービスのホスティングに使用されます。DockerfilesもDocker Composeも、Dockerアプリケーションを構築するための宣言的なメカニズムです。この記事では、Docker Composeを使ってサービスを拡張する方法についても紹介しています。

Alibaba Cloudは、さまざまなコンテナ化技術をテストするための信頼できるプラットフォームを提供します。

Alibaba Cloudのアカウントをお持ちではないですか？アカウントにサインアップすると、[最大1200ドル相当の40以上の製品を無料で](https://account.alibabacloud.com/register/intl_register.htm?spm=a2c65.11461447.0.0.56fb6c65ft0HZI)お試しいただけます。[Get Started with Alibaba Cloud](https://account.alibabacloud.com/register/intl_register.htm?spm=a2c65.11461447.0.0.56fb6c65ft0HZI)で詳細をご覧ください。


*本ブログは英語版からの翻訳です。オリジナルは[こちら](https://www.alibabacloud.com/blog/application-containerization_595769)からご確認いただけます。一部機械翻訳を使用しております。翻訳の間違いがありましたら、ご指摘いただけると幸いです。*

*アリババクラウドは日本に２つのデータセンターを有し、世界で60を超えるアベラビリティーゾーンを有するアジア太平洋地域No.1(2019ガートナー)のクラウドインフラ事業者です。
アリババクラウドの詳細は、こちらからご覧ください。
[アリババクラウドジャパン公式ページ](https://www.alibabacloud.com/ja)*