Azure での Docker コンテナーのデプロイ

読む時間の目安: 8 分

概要

Docker Azure 統合は、Azure コンテナーインスタンス(Azure Container Instances; ACI) の中で、ネイティブな Docker コマンドの利用を可能にします。 これを使って、クラウドに適したアプリケーションを構築し実行します。 この新たな仕組みによって、Docker Desktop と Microsoft Azure の緊密な統合が実現され、開発者にとっては、Docker CLI や VS Code 拡張機能を使ったアプリケーション実行が即座にできるようになり、またローカル開発環境とクラウドデプロイ環境をシームレスに切り替えることができます。

さらに Docker と Microsoft の開発技術の統合により、開発者が Docker CLI を用いる際には、以下のことが可能になります。

  • Azure に簡単にログインすることができます。
  • 1 つの Docker コマンドに対して ACI コンテキストを設定することができます。 これによってローカルコンテキストとクラウドコンテキストを切り替えられるようになり、アプリケーションの実行をすばやく簡単に行うことができます。
  • Compose を利用すれば、単一コンテナーアプリケーション、複数コンテナーアプリケーションの開発を単純化できます。 開発者にとってはクラウドコンテナーサービスに対して、シームレスな Docker 完全互換コマンドの実行が初めて可能になります。

ACI においてサポートされているコンテナー機能の一覧ACI においてサポートされている Compose 機能の一覧 も参照してください。

前提条件

Docker コンテナーを Azure にデプロイするには、以下の条件を満たしていることが必要です。

  1. Docker Desktop 最新版をダウンロードしインストールしていることが必要です。

    あるいは Docker ACI Integration for Linux をインストールしていることが必要です。

  2. Azure サブスクリプションを持っていることが必要です。 Azure free account にアクセスして取得操作を進めることができます。

ACI での Docker コンテナー実行

Docker は、単にローカルのコンテナーを実行するだけのものではなくなります。 docker run を使って ACI 上の Docker コンテナーをシームレスにデプロイできます。 あるいは Compose ファイルに定義されたマルチコンテナーのアプリケーションをdocker compose upコマンドを使ってデプロイできるようになります。

以下の節では ACI 上において Docker コンテナーをデプロイする手順を説明します。 ACI においてサポートされているコンテナー機能の一覧 も参照してください。

Azure へのログイン

以下のコマンドを実行して Azure にログインします。

$ docker login azure

ここからブラウザーが開いて Azure のログイン情報の入力が求められます。 Docker CLI からブラウザーが開かない場合は、そこから Azure デバイスコードフロー へ進み、手動で接続します。 なお Azure コマンドライン のログインは Docker CLI Azure ログインからは切り離されています。

これとは別に、対話形式でない方法(スクリプトや継続的インテグレーションの利用時)でのログインも可能です。 その場合には Azure サービスプリンシパルを利用しdocker login azure --client-id xx --client-secret yy --tenant-id zzのようにコマンド実行します。

メモ

Azure サービスプロバイダーを通じたログインでは、アクセストークンの有効期間は短いもの(通常は 1 時間)になっています。 だからといって、このトークンを自動的、透過的に更新することはできません。 サービスプロバイダーを利用したログイン中にそのアクセストークンの有効期間が過ぎた場合は、手動で再ログインしなければなりません。

Azure 上に複数のテナントを有している場合、--tenant-id オプションを単独で用いることもできます。

ACI コンテキストの生成

ログインした後は、ACI においてコンテナーをデプロイできるようにするために、ACI に関する Docker コンテキストを生成することが必要です。 ACI コンテキストの生成には Azure サブスクリプション、リソースグループ、地域設定が必要です。 たとえば新たなコンテキストとしてmyacicontextを生成することにします。

$ docker context create aci myacicontext

このコマンドは自動的に Azure ログイン情報を利用して、サブスクリプション ID やリソースグループを識別するものです。 コマンド実行においては、利用するサブスクリプションやグループを対話的に選択します。 必要であれば CLI の以下のようなフラグ--subscription-id--resource-group--locationを使って指定することもできます。

Azure アカウントにおいてリソースグループを 1 つも生成していない場合、docker context create aci myacicontext コマンドの実行によって、リソースグループが生成されます。 その際には特別なオプションを設定する必要はありません。

ACI コンテキストを生成したら、docker context ls コマンドを実行して Docker コンテキストの一覧を確認します。

NAME                TYPE                DESCRIPTION                               DOCKER ENDPOINT                KUBERNETES ENDPOINT   ORCHESTRATOR
myacicontext        aci                 myResourceGroupGTA@eastus
default *           moby              Current DOCKER_HOST based configuration   unix:///var/run/docker.sock                          swarm

コンテナーの実行

ログインを済ませて ACI コンテキストも生成したので、ACI 上にコンテナーをデプロイするための Docker コマンド操作を進めていきます。

新しく生成した ACI コンテキストを利用する方法は 2 つあります。 1 つは Docker コマンドにおいて--contextフラグを利用する方法です。 新たに生成した ACI コンテキストをここに指定して、コマンド実行を行います。

$ docker --context myacicontext run -p 80:80 nginx

もう 1 つはdocker context useを使ってコンテキストを切り替える方法です。 Docker コマンドの実行にあたって、対象とするコンテキストを ACI コンテキストとします。 たとえばdocker context useコマンドを利用して、Nginx コンテナーをデプロイしてみます。

$ docker context use myacicontext
$ docker run -p 80:80 nginx

コンテキストをmyacicontextに切り替えたら、docker psを使って ACI 上に動作するコンテナー一覧を確認することができます。

上に示した Nginx コンテナーの利用例において ps コマンドの出力結果にある「PORTS」カラムには、コンテナーが動作している IP アドレスとポートが表示されます。 たとえば52.154.202.35:80->80/tcpのような表示です。 そしてブラウザーからhttp://52.154.202.35にアクセスすれば、Nginx の Welcome ページが開きます。

コンテナーからログを確認するには以下を実行します。

$ docker logs <コンテナーID>

実行中のコンテナーにおいてコマンドを実行するには、以下のようにします。

$ docker exec -t <コンテナーID> COMMAND

ACI 上のコンテナーを停止して削除するには、以下のようにします。

$ docker stop <コンテナーID>
$ docker rm <コンテナーID>

コンテナーの削除にはdocker rmを用います。 コンテナーが実行中である場合には--forceフラグをつける必要があります。 あるいは削除の前にdocker stopを実行してコンテナーを停止させておくことが必要です。

メモ

ACI 上においてコンテナーを再起動する意味は、ローカル環境においてローカルな Docker コンテキストを利用している場合とは異なります。 ACI の場合、コンテナーはいったん初期状態にリセットされ、新たなノードとして起動されます。 これはつまり、コンテナー内のファイルシステムにおいて、ボリューム内に保存されていない状態があったとしたら、再起動時にそれらは失われるということです。

Compose アプリケーションの実行

ACI に対しては、Compose ファイルにて定義されたマルチコンテナーアプリケーションのデプロイと管理も可能です。 その際にはdocker compose コマンドを利用します。 同一の Compose アプリケーション内にあるコンテナーは、すべて同一のコンテナーグループ内において起動されます。 コンテナー間におけるサービス検出は、Compose ファイル内に指定されたサービス名を用いて行われます。 コンテナー間における名前解決は、/etc/hostsファイル内にサービス名を記述することによって実現されます。 /etc/hostsファイルは、コンテナーグループ内であればすべてのコンテナーが自動的に共有します。

ACI においてサポートされている Compose 機能の一覧 も参照してください。

  1. ACI コンテキストを利用していることが必要です。 これは--context myacicontextフラグを指定するか、あるいはデフォルトのコンテキストを設定するコマンドdocker context use myacicontextを実行します。

  2. docker compose updocker compose downを実行して、Compose アプリケーションの開始、停止ができることが必要です。

デフォルトにおいてdocker compose upは、カレントフォルダーのdocker-compose.yamlファイルを利用します。 ワーキングディレクトリは --workdir フラグにより指定することができます。 また Compose ファイルを直接docker compose --file mycomposefile.yaml upと指定することもできます。

Compose アプリケーションのデプロイの際に--project-nameフラグを使って、アプリケーション名を指定することもできます。 アプリケーション名の指定がなかった場合は、ワーキングディレクトリから名前が定められます。

Compose アプリケーションの一部として起動したコンテナーは、docker psを実行した際に、単一のコンテナーとともに表示されます。 そのコンテナーの ID は<Composeプロジェクト>_<サービス>という書式です。 こういったコンテナーは、個別に停止、起動、削除を行うことはできません。 これらは同一の ACI コンテナーグループを構成する一部であるからです。 各コンテナーのログはdocker logsを使って参照します。 デプロイを行った Compose アプリケーションの一覧はdocker compose lsを実行します。 この場合の一覧には Compose アプリケーションのみが表示され、docker runによって起動した単一のコンテナーは表示されません。 Compose アプリケーションを削除するにはdocker compose downを実行します。

メモ

現時点の Docker Azure 統合では、Compose アプリケーションを構成するコンテナーからのログを、すべて集めて取得するようなことはできません。

アプリケーションの更新

デプロイされた Compose アプリケーションに対しては、同一のプロジェクト名を用いて、docker compose --project-name PROJECT upのようにアプリケーションの再デプロイを行い、アプリケーションの更新を行うことができます。

アプリケーションを更新すると ACI ノードは再利用されます。 そして公開ポートに割り当てられていた IP アドレスは、どのようなものであっても同一値が維持されます。 ACI においては、既存アプリケーションへのアップデート内容によって制限が発生するものがあります(たとえば CPU/メモリの予約確保量を制限することはできません)。 その場合は、アプリケーションを新たに一からデプロイすることが必要です。

すでにデプロイされた Compose ファイルに対してdocker compose upを実行すれば、アプリケーションを更新するのがデフォルトの動作です。 そのときにはデフォルトで、Compose ファイルがあるディレクトリ名から Compose プロジェクト名を取り出します。 Compose アプリケーションを完全にリセットしたいのであれば、再度docker compose upを実行する前に、明示的にdocker compose downを実行することが必要です。

リソースの解放

単独のコンテナーや Compose アプリケーションはdocker pruneコマンドを使って ACI から削除することができます。 docker pruneコマンドは、現在実行されていないデプロイ内容を削除します。 実行中のデプロイ内容を削除するには--forceを指定します。 --dry-runオプションを使えば、削除予定のデプロイ一覧が表示されます。 ただしこれは実際に削除を行うものではありません。

$ ./bin/docker --context acicontext prune --dry-run --force
Resources that would be deleted:
my-application
Total CPUs reclaimed: 2.01, total memory reclaimed: 2.30 GB

ポートの公開

単独のコンテナーや Compose アプリケーションは、オプションとしてポートを公開することができます。 単独のコンテナーの場合は、docker runコマンドに--publish-p)フラグをつけてdocker run -p 80:80 nginxのように実行します。

また Compose アプリケーションの場合は、Compose ファイルのサービス定義において、公開するポートを設定する必要があります。

services:
  nginx:
    image: nginx
    ports:
      - "80:80"

メモ

ACI ではポートマッピングを行うことはできません(つまりポート公開においてポート番号を変更することはできません)。 したがって ACI へのデプロイにあたって公開元も公開先も同一のポートでなければなりません。

Compose アプリケーション内に含まれるコンテナーはすべて、同一の ACI コンテナーグループとしてデプロイされます。 同一の Compose アプリケーション内の異なるコンテナーは、ACI へのデプロイに際して同一のポートを公開することはできません。

アプリケーションにおいてポート公開を行う際には、デプロイするアプリケーション(単独のコンテナーまたは Compose アプリケーション)に対応するコンテナーグループに対して、ランダムな公開 IP アドレスが関連づけられるのがデフォルトです。 この IP アドレスはdocker psを使ってコンテナーを一覧表示したり、docker inspectを実行したりしたときに確認することができます。

DNS ラベル名

ランダムな IP アドレスに対するポート公開に加えて、アプリケーションを FQDN の形式で公開するための DNS ラベル名を指定することができます。 たとえば<NAME>.region.azurecontainer.ioという形式です。

この名前はdocker runの実行時に--domainnameフラグを用いて設定します。 あるいは Compose ファイル内のdomainname項目を利用してdocker compose upにより実現します。

services:
  nginx:
    image: nginx
    domainname: "myapp"
    ports:
      - "80:80"

メモ

複数のサービスに対してdomainnameを設定していたとしても、Compose アプリケーションのドメイン設定が行われるのは一度だけです。 したがってそれらは同一でなければなりません。

FQDN である<DOMAINNAME>.region.azurecontainer.ioが利用可能です。

ACI コンテナー内での Azure ファイル共有のボリュームとしての利用

コンテナーや Compose アプリケーションにおいてボリュームを使ったデータ保存を行っている場合でも、デプロイすることが可能です。 Azure ファイル共有を使えば、ACI コンテナーに対してのボリュームをサポートしています。

既存の Azure ファイル共有を利用して、ストレージアカウント名 がmystorageaccount、ファイル共有名がmyfileshareであるとしたときに、デプロイにおけるrunコマンド実行を以下のように指定できます。

$ docker run -v mystorageaccount/myfileshare:/target/path myimage

これにより実行中のコンテナーからは、ファイル共有内容は/target/pathに見えるようになります。

Compose アプリケーションにおいて、ボリュームの指定は Compose ファイル内において以下のような文法に従う必要があります。

myservice:
  image: nginx
  volumes:
    - mydata:/mount/testvolumes

volumes:
  mydata:
    driver: azure_file
    driver_opts:
      share_name: myfileshare
      storage_account_name: mystorageaccount

メモ

Compose ファイル内においては、ボリュームを短い文法で記述することはできません。 ボリューム定義というものは、ローカルのバインドマウント向けを目的としているためです。 Compose ファイルにおいては、ボリュームドライバーやそのオプションを利用すれば、ボリューム定義がより明確になります。

単一または複数コンテナーのデプロイにおいて Docker CLI は、Azure ストレージアカウントに対する鍵情報を取得するために Azure ログインを行います。 そしてこの鍵をコンテナーデプロイ情報に利用します。 こうしてコンテナーがボリュームにアクセスできるようになります。 Azure ログインによってアクセスするストレージアカウント内であれば、ボリュームはどのファイル共有からでも利用できます。 ボリュームマウントの際にはrw(読み書き)またはro(読み取り専用)を指定します(デフォルトはrwです)。

Azure ボリュームの管理

ACI Docker コンテキストを利用して、コンテナーや Compose アプリケーション内で用いるボリュームを生成するには、docker volume create コマンドを実行します。 そこで Azure ストレージアカウント名とファイル共有名を指定します。

$ docker --context aci volume create test-volume --storage-account mystorageaccount
[+] Running 2/2
 ⠿ mystorageaccount  Created                         26.2s
 ⠿ test-volume       Created                          0.9s
mystorageaccount/test-volume

ストレージアカウントが存在しない場合、このコマンドがデフォルト SKU として 標準 LRS を利用してストレージアカウントを新規生成します。 そしてリソースグループや Docker ACI コンテキストに関連するディレクトリを生成します。

既存のストレージアカウントを指定した場合、このコマンドはそのアカウント内にファイル共有を新規生成します。

$ docker --context aci volume create test-volume2 --storage-account mystorageaccount
[+] Running 2/2
 ⠿ mystorageaccount   Use existing                    0.7s
 ⠿ test-volume2       Created                         0.7s
mystorageaccount/test-volume2

別の方法として Azure ストレージアカウントを生成するか、 Azure ポータル、つまりazコマンドライン を用いてファイル共有を生成することができます。

コンテナーや Compose アプリケーションにおいて利用可能なボリュームの一覧を確認することができます。

$ docker --context aci volume ls
ID                                 DESCRIPTION
mystorageaccount/test-volume       Fileshare test-volume in mystorageaccount storage account
mystorageaccount/test-volume2      Fileshare test-volume2 in mystorageaccount storage account

ボリュームと対応する Azure ファイル共有を削除するにはvolume rmコマンドを実行します。

$ docker --context aci volume rm mystorageaccount/test-volume
mystorageaccount/test-volume

これによって Azure ファイル共有とこれに関連するデータは、完全に削除されます。

Azure においてボリュームを削除するとこのコマンドは、指定されたファイル共有が、そのストレージアカウントにおいてのみ利用されているファイル共有であるかどうかをチェックします。 そのストレージアカウントがdocker volume createコマンドによって作り出されたものである場合、docker volume rm コマンドは、ストレージアカウントがファイル共有を持っていなければ、ストレージアカウントも削除します。 逆にストレージアカウントが(たとえば Azure ポータルやazコマンドを使った場合のように)docker volume create 以外において生成されたものである場合は、docker volume rm はストレージアカウントを削除しません。 そのアカウントが一つのファイル共有も残っていなかったとしてもです。

環境変数

docker runの実行時には、--envフラグを利用して ACI コンテナーに環境変数を受け渡すことができます。 Compose アプリケーションの場合は、Compose ファイル内においてサービス項目environmentまたはenv-fileにおいて環境変数を指定するか、あるいはコマンドラインフラグ--environmentを利用して指定します。

ヘルスチェック

コンテナーのヘルスチェックを行うことができます。 docker runの実行においては--healthcheck-をプレフィックスに持つフラグを利用します。 また Compose ファイルにおいては、そのサービスのhealthcheckセクションを利用します。

ヘルスチェックは ACI のLivenessProbeに変換されます。 ACI ではヘルスチェックコマンドを定期的に実行します。 チェックに失敗したとき、そのコンテナーは停止されます。

したがってヘルスチェックには再起動ポリシーを含めて利用することが必要であり、コンテナーの停止後に再起動させることが必要です。 docker runにおけるデフォルトの再起動ポリシーはnoであり、これはコンテナーを再起動しません。 Compose に対するデフォルトの再起動ポリシーはanyであり、これは常にサービスコンテナーを再起動します。

docker runの実行例は以下のとおりです。

$ docker --context acicontext run -p 80:80 --restart always --health-cmd "curl http://localhost:80" --health-interval 3s  nginx

Compose ファイルの利用例は以下のとおりです。

services:
  web:
    image: nginx
    deploy:
      restart_policy:
        condition: on-failure
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:80"]
      interval: 10s

プライベートな Docker Hub イメージと Azure コンテナーレジストリの利用

どのようなコンテナーレジストリにホストされている ACI であっても、プライベートイメージをデプロイすることができます。 docker rundocker compose upを実行するためには、その前にdocker loginを使ってそのレジストリにログインしておくことが必要です。 Docker CLI では、デプロイイメージに対するレジストリログイン情報を取得した上で、資格情報やイメージデプロイ情報を ACI に送信します。 Azure コンテナーレジストリ(Azure Container Registry; ACR)の場合は、Azure ログインから ACR へのログインを自動的に行います。 Azure ログインから ACR へのアクセスができていれば、わざわざ ACR レジストリへのログインを手動で行う必要はなくなります。

名前空間としての ACI リソースグループの利用

ACI に関連づける Docker コンテキストは、複数用意することができます。 個々のコンテキストは、一意の Azure リソースグループに関連づいていることが必要です。 こうしておくと Docker コンテキストを名前空間として利用することができます。 docker context use <CONTEXT> を実行することで、複数の名前空間を切り替えることができます。

docker ps コマンドを実行すると、現在の Docker コンテキスト内にあるコンテナーのみが一覧表示されます。 Docker コンテキストが異なれば、コンテナー名や Compose アプリケーション名が同一であっても、競合することにはなりません。

Linux における Docker Compose CLI のインストール

Docker Compose CLI は、Azure コンテナーインスタンス(ACI)上でのコンテナー実行と管理をサポートします。

インストールの前提条件

インストールスクリプト

新たな CLI は、インストールスクリプトを利用してインストールします。

$ curl -L https://raw.githubusercontent.com/docker/compose-cli/main/scripts/install/install_linux.sh | sh

手動インストール

Docker ACI 統合の CLI は、最新版 ページからダウンロードすることができます。

入手したらこれを実行可能にします。

$ chmod +x docker-aci

ローカルの Docker Engine の利用を有効にするため、そして既存の Docker コンテキストを利用可能にするため、既存の Docker CLI はcom.docker.cliとして、パス上のどこかに配置する必要があります。

$ ln -s /path/to/existing/docker /directory/in/PATH/com.docker.cli

メモ

環境変数PATHは、複数ディレクトリをコロンで区切るものであり、左にあるものが優先されます。 内容を確認するにはecho $PATHを実行します。 既存の Docker CLI へのパスはwhich dockerを使って確認できます。 なお上のリンクを生成する際には root 権限を要するかもしれません。

Docker Engine が インストール されている Ubuntu 20.04 の場合、初期状態では以下のようになっています。

$ echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin
$ which docker
/usr/bin/docker
$ sudo ln -s /usr/bin/docker /usr/local/bin/com.docker.cli

新しい CLI が動作しているかどうかを確認するには、デフォルトのコンテキストを使って CLI を実行します。

$ ./docker-aci --context default ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
$ echo $?
0

ACI と統合された CLI を、デフォルトの Docker CLI とするためには、PATH 上のディレクトリにおいて、既存の Docker CLI よりも優先されるようなディレクトリに移動させる必要があります。

再び Ubuntu 20.04 の例を見ます。

$ which docker
/usr/bin/docker
$ echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin
$ sudo mv docker-aci /usr/local/bin/docker
$ which docker
/usr/local/bin/docker
$ docker version
...
 Azure integration  0.1.4
...

サポートされているコマンド

Docker ACI 統合の CLI をインストールしたら、--help をつけてコマンド実行し、この時点でのコマンド一覧を確認します。

アンインストール

Docker Azure 統合の CLI を削除する場合は、ダウンロードしたバイナリとcom.docker.cliPATH上から削除します。 スクリプトを通じてインストールを行った場合は、以下により削除することができます。

$ sudo rm /usr/local/bin/docker /usr/local/bin/com.docker.cli

フィードバック

Docker Azure 統合ベータ版を利用していただき、ありがとうございます。 みなさんからのフィードバックが大変重要です。 フィードバックをいただくには、Github レポジトリ compose-cli に issue をあげてください。

Docker, Azure, Integration, ACI, context, Compose, cli, deploy, containers, cloud