[GCP]VM インスタンス内でDockerコンテナを起動して、ブラウザからアクセスする

こんにちは、システムエンジニアの Kota です。以前の記事で、 AWS に EC2 を構築して、Docker を install し、Hello world! と表示させました。今回は、同じことを Google Cloud Platform ( GCP ) で実践したいと思います。

  • 対象の読者
    • 開発環境で Docker を使っているけど、デプロイにも使いたい方
    • Docker、GCP に触れてみたい方
    • AWS は触ったことあるけど、GCP は触ったことがない方
    • インフラに興味がある方

まずは、完成イメージをご紹介します。

完成イメージ

手順としては以下のようになります。

作業中は、完成イメージを持っているとより理解が深まりやすいと思います。

今回の作業は、GCP のアカウントが必要になりますので、まだお持ちでない方は下記のリンクよりアカウントを作成してください。

では、早速やっていきましょう!

1. 新しいプロジェクトを作成する

GCPのプロジェクトとは、Compute EngineやCloud StorageなどのGCPのサービスで作成するリソースをまとめて管理する単位です。
GCPでは、課金の対象がプロジェクト毎に分けられます。
プロジェクトの作成と管理
GCPのコンソールを開くと、デフォルトで、「My First Project」というプロジェクト名のプロジェクトが作成されていると思います。
今回は、「Hello World project」として、新しいプロジェクトを作成しましょう。



2. VPC と サブネットの構築

プロジェクトが作成できたら、次にVPCとサブネットを作成していきます。
GCP と AWS の VPC では以下のような違いがあります。

  • AWS の VPC

    • リージョンの中に VPC が存在する( リージョンごとに VPC を作成 )
    • サブネットを AZ ごとに作成
    • IGW (インターネットゲートウェイ) は VPC に紐付く
  • GCP の VPC

    • 全リージョンに跨っており、グローバルで管理するネットワークになっている
    • VPC 作成時に IP 指定がない( IP はサブネットに紐付く )
    • IGW を持たない( IGW はサブネットに紐付く )

それではプロジェクトのダッシュボードを開いて下さい。

サイドバーのネットワーキングからVPCネットワークを選択して下さい。

デフォルトでは、default という VPC ネットワークと、 default ネットワークに属する各リージョンのサブネットが表示されています。
上部の「 VPC ネットワークを作成」から作成画面を開きます。

VPCの名前は「hello-world-vpc」とします。
Descriptionは特に記入なしで、VPC ネットワーク ULA の内部 IPv6 範囲 は無効とします。
サブネット作成モードはカスタムを選択します。

サブネットの名前は、「hello-world-subnet」とします。
Descriptionは特に記入なしで、リージョンは「asia-northeast1」にします。
IP スタックタイプは、IPv4(シングル スタック)を選択します。
IPv4 範囲は 「192.168.1.0/24」と指定しておきます。
限定公開の Google アクセス、フローログ はオフを選択しておきます。

ファイアウォール ルールは後ほど編集します。
動的ルーティングモードはリージョンを選択し、最大伝送単位(MTU)はデフォルトの 1460 を選択します。

全て設定できたら、作成をボタンを押します。
一覧画面に「hello-world-vpc」が表示されています。
一覧の各VPCの名前をクリックすると詳細を閲覧でき、ここから各種設定の編集などを行うことができます。

3. ファイアウォールを設定する

前提として、GCP では VPC とインスタンスにファイアウォールを設定できます。
先ほど作成した VPC では、ファイアウォールが未設定ですので、現在の状態では、このネットワーク内にインスタンスを作成しても接続できない状態になっています。ここでは、ssh 接続するためのファイアウォールルールを設定していきます。(http 接続などのルールはインスタンス作成時に設定できます。)詳細画面から編集していきましょう。
VPCの一覧画面から先ほど作成した「hello-world-vpc」を選択し、詳細画面を開きます。
ファイアウォールルールのタブ > ファイアウォール ルールを追加を選択して下さい。

入力画面が開いたら、下記の通りに入力していきます。

4. VM インスタンスを立てる

次は、先ほど作成した VPC 内にインスタンスを立ち上げます。
コンソールの Compute Engine > VM インスタンスをクリックします。

初めてであれば、下記の画面が表示されると思いますので、インスタンスを作成をクリックします。

作成画面が開いたら、下記の通り設定していきます。






注意

今回はあくまでも実験用として http トラフィックを許可していますが、実運用として使う場合は、https 化して下さい。

入力が済んだら、作成ボタンをクリックします。
しばらくすると、一覧に表示されます。

5. SSH でインスタンスにアクセスする

次に 4. で作成したインスタンスに SSH 接続できるか確認してみましょう。
接続方法はいくつかありますが、今回は gcloud コマンドで接続したいと思います。
下記画像の赤枠内の▼をクリックします。

次に 「gcloud コマンドを表示」 クリックします。

すると、コマンドが表示されたモーダルが開きますので、表示されているコマンドをコピーし、
下部の「 CLOUD SHELL で実行」をクリックします。

画面下部にターミナルが表示されたと思いますので、先ほどコピーしたコマンドを貼り付け、実行して下さい。

※ 初回は、 ssh キーを作成したり、パスワードを設定したりするかと思います。

下記のように表示されれば、接続成功です。

XXXXXX@cloudshell:~ (hello-wolrd-project-351708)$ gcloud compute ssh --zone "asia-northeast1-a" "hello-world-instance"  --project "hello-wolrd-project-351708"
Enter passphrase for key '/home/XXXXXX/.ssh/google_compute_engine':
Welcome to Ubuntu 18.04.6 LTS (GNU/Linux 5.4.0-1075-gcp x86_64)

 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/advantage

  System information as of Wed Jun 15 04:38:36 UTC 2022

  System load:  0.0               Processes:              119
  Usage of /:   37.5% of 9.52GB   Users logged in:        0
  Memory usage: 29%               IP address for ens4:    192.168.1.2
  Swap usage:   0%                IP address for docker0: 172.17.0.1

 * Super-optimized for small spaces - read how we shrank the memory
   footprint of MicroK8s to make it the smallest full K8s around.

   https://ubuntu.com/blog/microk8s-memory-optimisation

2 updates can be applied immediately.
To see these additional updates run: apt list --upgradable

New release '20.04.4 LTS' available.
Run 'do-release-upgrade' to upgrade to it.

*** System restart required ***
Last login: Wed Jun 15 04:38:03 2022 from 34.81.211.70
XXXXXX@hello-world-instance:~$

そのまま、次の章でインスタンスに docker を install していきます。

6. VM インスタンス に Docker を install する

こちらの Docker 公式のドキュメントを参考にインスタンスに Docker を install していきます。

まずは、apt の update と、必要な package を install します。

 $ sudo apt-get update
 $ sudo apt-get install \
    ca-certificates \
    curl \
    gnupg \
    lsb-release

次に Docker の公式 GPG キーを追加します。

$ sudo mkdir -p /etc/apt/keyrings
$ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg

そして、以下のコマンドを実行してリポジトリを設定します。

$ echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
  $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

上記のコマンドを実行したら、再度 apt を update し、Docker Engine、containerd、Docker Compose を install します。

$ sudo apt-get update
$ sudo apt-get install docker-ce docker-ce-cli containerd.io docker-compose-plugin

正常に install できているか確認してみましょう。
以下のコマンドを実行してください。

$ sudo docker info

下記のように表示されれば、install 成功です。

XXXXXXX@hello-world-instance:~$ sudo docker info
Client:
 Context:    default
 Debug Mode: false
 Plugins:
  app: Docker App (Docker Inc., v0.9.1-beta3)
  buildx: Docker Buildx (Docker Inc., v0.8.2-docker)
  compose: Docker Compose (Docker Inc., v2.6.0)
  scan: Docker Scan (Docker Inc., v0.17.0)

Server:
 Containers: 0
  Running: 0
  Paused: 0
  Stopped: 0
 Images: 1
 Server Version: 20.10.17
 Storage Driver: overlay2
  Backing Filesystem: extfs
  Supports d_type: true
  Native Overlay Diff: true
  userxattr: false
 Logging Driver: json-file
 Cgroup Driver: cgroupfs
 Cgroup Version: 1
 Plugins:
  Volume: local
  Network: bridge host ipvlan macvlan null overlay
  Log: awslogs fluentd gcplogs gelf journald json-file local logentries splunk syslog
 Swarm: inactive
 Runtimes: io.containerd.runtime.v1.linux runc io.containerd.runc.v2
 Default Runtime: runc
 Init Binary: docker-init
 containerd version: 10c12954828e7c7c9b6e0ea9b0c02b01407d3ae1
 runc version: v1.1.2-0-ga916309
 init version: de40ad0
 Security Options:
  apparmor
  seccomp
   Profile: default
 Kernel Version: 5.4.0-1078-gcp
 Operating System: Ubuntu 18.04.6 LTS
 OSType: linux
 Architecture: x86_64
 CPUs: 2
 Total Memory: 973.3MiB
 Name: hello-world-instance
 ID: TMIZ:S6PL:RWNQ:BYIQ:CKFC:J3AX:H6SY:2XT5:BEXO:7W33:Q5VV:OMKP
 Docker Root Dir: /var/lib/docker
 Debug Mode: false
 Registry: https://index.docker.io/v1/
 Labels:
 Experimental: false
 Insecure Registries:
  127.0.0.0/8
 Live Restore Enabled: false

WARNING: No swap limit support

今のままだと、docker コマンドを打つ際に、sudo を付けなければなりません。
これは、現在のユーザーに docker コマンドの操作権限がない為です。
ユーザーに操作権限を与える為、以下のコマンドを実行します。

$ sudo usermod -a -G docker [user name]

$ whouser name を確認できます。

上記のコマンドは、操作権限をもつ docker グループに ユーザー を加えるコマンドです。詳しく知りたい方は、公式ドキュメントを参照して下さい。
グループの追加は、シェルを起動し直さないと反映されないので、一度 exit でサーバーからログアウトし、ログインし直して下さい。
sudo なしで、docker info と実行し、先ほどと同じ内容の出力がされれば、グループへの追加が成功しています。

7. インスタンス内でコンテナを立ち上げ、ブラウザからアクセスする

さて、それでは最後の工程です。
インスタンスに ssh で接続している状態だと思いますので、そのまま作業ディレクトリを作成しましょう。

XXXXXXX@hello-world-instance:~$ mkdir hello-world-docker
XXXXXXX@hello-world-instance:~$ cd hello-world-docker/

そして、Hello world! と表示させる為の html ファイルを用意します。

XXXXXX@hello-world-instance:~/hello-world-docker$ vi hello-world.html

vi が開きますので、i で insert mode にし、

Hello world! と記述して、esc キー、 :wq で保存します。

ls コマンドでディレクトリに今作成した html ファイルが作成されていると思います。

XXXXXX@hello-world-instance:~/hello-world-docker$ ls
hello-world.html

次にDockerimage を作成する為に、Dockerfile を作成、編集していきます。

今回も前回と同様、webサーバーに nginx を使用します。先ほど作成した、html ファイルを nginx 上で表示させます。

XXXXXX@hello-world-instance:~/hello-world-docker$ vi Dockerfile

Dockerfile

FROM nginx
COPY ./hello-world.html /usr/share/nginx/html/

nginx では、デフォルトの状態だと/usr/share/nginx/html/ 配下がブラウザからアクセスした際の初期表示になっているので、./hello-world.html をコピーします。

編集出来たら、先ほどと同じように保存して下さい。

そして、作成したDockerfile を元に image を build します。

下記のコマンドを実行します。

XXXXXX@hello-world-instance:~/hello-world-docker$ docker build -t hello-world-docker .

build が完了したら、container を起動します。

下記のコマンドを実行して下さい。

XXXXXX@hello-world-instance:~/hello-world-docker$ docker run --rm -d -p 80:80 hello-world-docker
  • 今回はあくまで実験として作業をしているので、--rm オプションをつけてコンテナ終了時に削除していますが、本番を想定する場合は、オプションを付与しなくても良いかも知れません。

docker ps コマンドでコンテナの STATUS が UP になっていれば、起動に成功しています。

XXXXXX@hello-world-instance:~/hello-world-docker$ docker ps
CONTAINER ID   IMAGE                COMMAND                  CREATED          STATUS          PORTS                               NAMES
a2f44503699c   hello-world-docker   "/docker-entrypoint.…"   20 seconds ago   Up 19 seconds   0.0.0.0:80->80/tcp, :::80->80/tcp   peaceful_faraday

ここまでで、全ての作業が完了です。

それではブラウザからアクセスしてみましょう。

コンソール画面で VM インスタンスの一覧を開き、4. で作成した インスタンスの外部IP をコピーし、ブラウザで IPアドレス / hello-world.html でアクセスします。

無事に Hello world! と表示させることができました!

さて、如何だったでしょうか?
今回は、GCP に VM インスタンス を立て、その中で Docker コンテナを起動させ、ブラウザからアクセスすることをハンズオン形式でやってみました。前回の AWS と概念が違う部分もありましたが、大筋は同じ流れで作業を進めて上手く表示させることができました。
今回も最後まで読んで頂き、ありがとうございました!