はじめに
「やっぱり作ったアプリはデプロイしたい…!」「格好良くIaCも触りたい…!」という独学未経験の初心者の奮闘記録です。
もし間違い等ありましたらご指摘頂けると嬉しいです。
Terraformって何なの?
インフラ構成をコードで管理できるIaC(Infrastructure as Code)ツールの1つ。
クラウドインフラの構成は、コンソール画面やSDKを用いて行えますが、どういった構成にしているかが見えず共有しにくくなります。また、以前の構成に戻したくなっても操作が面倒です。
それに対してIaCでは、コードで構成を管理できるので、インフラを可視化、共有がしやすく、変更履歴も残せます。
細かい部分については、以下の記事をとてもわかりやすいのでご覧ください。
Terraformの手順
Terraformのバージョン管理を簡単に切り替えながら取り扱えるので、tfenvをインストールします。
$ brew install tfenv # tfenvのインストール
$ tfenv install x.x.x<使用したいバージョン> # 使用したいTerraformのバージョンをインストール
$ tfenv use x.x.x<使用したいバージョン> # 使用したいTerraformのバージョンを選択
素のTerraformをインストールしても良いです。そして以下の順序でインフラ構成を適用します。
- プロジェクトのルートディレクトリにて、Terraform用ディレクトリを作成します。
- 作成したディレクトリに移動し、
main.tf
を作成、インフラ構成を書く。以降、ディレクトリ移動せず実施する。 -
terraform init
を実行、初期化する。 -
terraform plan
を実行、作成されるインフラ構成の確認をする。 -
terraform apply
を実行、④で確認した内容でインフラを構成する。エラーがあれば吐かれる。
私はよく確認しておらず、ディレクトリに移動しinit
することを知りませんでした。変なところでハマってしまい時間を費やしてまった…。
Terraformの構成
今回、デプロイ先はCloud Runで、さらにnginxを使いたかったのでコンテナを2つ立ち上げる必要がありました。「どうしたらええんや…」の頭を抱えていたところ、以下の記事を見つけましたので参考にさせて頂きました。
Cloud Runの認証設定
TerraformがCloud Runにアクセス出来るよう、まず認証設定をします。
以下2点を済ませておきましょう。
-
gcloud CLI
をインストール - GCPにてプロジェクトを作成
作成したプロジェクトIDを用いて、gcloud
での操作対象としてアクティブにします。
$ gcloud config set project <プロジェクトID>
サービスアカウントを作成します。
gcloud iam service-accounts create サービスアカウントの名前 \
--description="説明文(任意)" \
--display-name="表示名"
サービスアカウントに権限を付与します。
gcloud projects add-iam-policy-binding <プロジェクトID> \
--member="serviceAccount:<作成したサービスアカウント名>@<プロジェクトID>.iam.gserviceaccount.com" \
--role="roles/editor"
サービスアカウントキーをローカルに取得します。
gcloud iam service-accounts keys create <任意のパス>/key.json \
--iam-account <作成したサービスアカウント名>@<プロジェクトID>.iam.gserviceaccount.com
サービスアカウントキーを用いた認証は公式で推奨されてませんが、手早くデプロイするため採用しました。
キーの管理のベストプラクティスが紹介されていますので、参考にし管理には十分注意しましょう。
公式の認証方法の選択フローもあるので、キーを使いたくない場合はこちらも参考にしてください。
Artifact Registryの設定
provider "google" {
project = var.project_id
region = var.default_region
credentials = file("path/to/key.json") # サービスアカウントキーのパス
}
provider "google-beta" {
project = var.project_id
region = var.default_region
}
resource "google_artifact_registry_repository" "your_project_image_repository" {
provider = google-beta
location = var.default_region
repository_id = var.repository_id
description = "your-project"
format = "DOCKER"
cleanup_policy_dry_run = false
cleanup_policies {
id = "keep_minimum-versions"
action = "KEEP"
most_recent_versions {
keep_count = 3
}
}
}
variable "default_region" {
description = "default region"
type = string
default = "asia-northeast1"
}
variable "project_id" {
description = "project id"
type = string
default = "your-api-project"
}
variable "repository_id" {
description = "repository id"
type = string
default = "your-project-image-repository"
}
まずは、コンテナを立ち上げるためのdockerイメージのリポジトリを作ります。
上記の内容でterraform init
▷ terraform plan
▷ terraform apply
を実行することで、Artifact Registryが作成されます。
Artifact Registryにdockerイメージをプッシュする
デプロイ先でコンテナを立ち上げるためのdockerイメージを、Dockerfileがあるディレクトリでビルドし、プッシュします。
ちなみにnginx側とアプリ側のDockerfileは以下のようになっています。
FROM nginx:1.17.4-alpine
RUN rm /etc/nginx/conf.d/default.conf
COPY default.conf /etc/nginx/conf.d
FROM python:3.11
ENV PYTHONDONTWRITEBYTECODE=1
ENV PYTHONUNBUFFERED=1
WORKDIR /code
COPY requirements.txt ./
RUN python3 -m pip install --upgrade pip setuptools
RUN pip install -r requirements.txt
COPY . ./
CMD exec gunicorn --bind :$PORT --workers 1 --threads 8 --timeout 0 config.wsgi:application
ビルドの際、公式の通り、リージョン(asia-northeast1
)やホスト名(docker.pkg.dev
)、プロジェクトIDなどを含めてタグ付けします。
イメージにレジストリ名をタグ付けする
Docker イメージにレポジトリ名をタグ付けすると、イメージを特定の場所に push するように docker push コマンドが構成されます。
docker build --platform linux/amd64 \
-f Dockerfile \
-t asia-northeast1-docker.pkg.dev/your-api-project/your-project-image-repository/your-web-back-image:v1 .
docker push asia-northeast1-docker.pkg.dev/your-api-project/your-project-image-repository/your-web-back-image:v1
docker build --platform linux/amd64 \
-f Dockerfile \
-t asia-northeast1-docker.pkg.dev/your-api-project/your-project-image-repository/your-nginx-image:v1 .
docker push asia-northeast1-docker.pkg.dev/your-api-project/your-project-image-repository/your-nginx-image:v1
ビルドする際、--platform
でOSとアーキテクチャをlinux/amd64に指定しましょう。私はここで、エラーにハマりました…。
Cloud Runの設定
Cloud Runの構成のため、main.tf
に以下を追記します。
resource "google_cloud_run_v2_service" "your-project-name" {
provider = google-beta
name = "your-project-name"
location = var.default_region
ingress = "INGRESS_TRAFFIC_ALL"
template {
containers {
name = "your-web-back-container"
image = "asia-northeast1-docker.pkg.dev/${var.project_id}/${var.repository_id}/your-web-back-image:v1"
env {
name = "PORT"
value = "8000"
}
startup_probe {
failure_threshold = 1
initial_delay_seconds = 0
timeout_seconds = 240
period_seconds = 240
tcp_socket {
port = 8000
}
}
}
containers {
name = "your-nginx-container"
image = "asia-northeast1-docker.pkg.dev/${var.project_id}/${var.repository_id}/your-nginx-image:v1"
ports {
container_port = 8080
}
depends_on = [ "your-web-back-container" ]
startup_probe {
failure_threshold = 1
initial_delay_seconds = 0
timeout_seconds = 240
period_seconds = 240
tcp_socket {
port = 8080
}
}
}
scaling {
min_instance_count = 0
max_instance_count = 1
}
}
traffic {
type = "TRAFFIC_TARGET_ALLOCATION_TYPE_LATEST"
percent = 100
}
}
再度、terraform init
▷ terraform plan
▷ terraform apply
を実行して、無事にCloud Runにデプロイ出来ました!
おわりに
アプリを公開するって本当に大変ですね…。