2024年12月21日
こんにちは、
またAI/BI部のK.です。
本日は、TerraformとCoder CDEを活用してインフラ自動化についてご紹介します。
インフラストラクチャ・アズ・コード(IaC)は、インフラストラクチャを手動のプロセスではなくコードを使用して管理およびプロビジョニングするプラクティスです。
アプリケーションコードと同様に、インフラストラクチャコードはバージョン管理システム(VCS)に保存され、
インフラストラクチャの変更が追跡可能でスケーラブルであることを保証します。
インフラストラクチャを記述的で機械可読なファイルで定義することにより、IaCは自動化、一貫性、および再現性を可能にし、人為的なエラーを減らします。
Terraformとは、開発者がHCL(HashiCorp Configuration Language)と呼ばれる高水準の構成言語を使用して、
アプリケーションを実行するためのクラウドまたはオンプレミスのインフラストラクチャーの望ましい「最終状態」を記述できる宣言型コーディング・ツールです。
Coderは自己ホスト型のオープンソースのクラウド開発環境で、どのクラウド、IDE、OS、Gitプロバイダー、IDPとも連携します。
リモート開発の利点
Coderの特徴:
CoderはGNU Affero General Public License v3.0の下で無料でオープンソースです。プレミアムライセンスも利用可能です。
Coderの動作:
⇒ CoderワークスペースはTerraformで表現され、AWS EC2、Azure、Google Cloud、Kubernetesなどのテンプレートが利用可能です。
Coderは以下のものではありません:
Coderは自己ホスト型のソリューションで、プライベートデータセンターやAWS、Azure、GCPなどのクラウドサービスにホストする必要があります。
そして、なんでTerraformの紹介にCoderが入っているの?
⇒ TerraformはCoderで最初にサポートされたIaCプロビジョナーであり、Coder管理者がTerraformリソースをCoderワークスペースとして定義できます。
今回はCoderのインストールしたり、Terraformのベーシック構文を理解したり、簡単にDocker Containerで開発環境を構築してみようと思います。
まず、公式インストールガイドを目を通していただく: Coder/Docs/Install
今回Ubuntu 22.04環境でDocker Composeを使用して、Coderをインストールすることになります。
docker-compose.yaml(Github/coder/docker-compose.yaml)
services:
coder:
image: ghcr.io/coder/coder:${CODER_VERSION:-latest}
ports:
- "8080:8080"
env_file:
- ./.env
environment:
CODER_PG_CONNECTION_URL: "postgresql://${POSTGRES_USER:-username}:${POSTGRES_PASSWORD:-password}@database/${POSTGRES_DB:-coder}?sslmode=disable"
CODER_HTTP_ADDRESS: "${CODER_HTTP_ADDRESS}"
CODER_ACCESS_URL: "${CODER_ACCESS_URL}"
user: root
privileged: true
group_add:
- "999" # docker group on host
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- coder_home:/home/coder
depends_on:
database:
condition: service_healthy
database:
image: "postgres:16"
ports:
- "5432:5432"
environment:
POSTGRES_USER: ${POSTGRES_USER:-username}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-password}
POSTGRES_DB: ${POSTGRES_DB:-coder}
volumes:
- coder_data:/var/lib/postgresql/data
healthcheck:
test:
[
"CMD-SHELL",
"pg_isready -U ${POSTGRES_USER:-username} -d ${POSTGRES_DB:-coder}",
]
interval: 5s
timeout: 5s
retries: 5
volumes:
coder_data:
coder_home:
.env
POSTGRES_USER=coder
POSTGRES_PASSWORD=<openssl rand -hex 16>
POSTGRES_DB=coder
CODER_ACCESS_URL=http://192.168.0.99:8080
CODER_HTTP_ADDRESS=0.0.0.0:8080
CODER_TLS_ENABLE=false
CODER_TLS_ADDRESS=0.0.0.0:8443
CODER_REDIRECT_TO_ACCESS_URL=true
CODER_TELEMETRY_ENABLE=false
そして、 docker compose up -d
管理者(admin)の情報を登録すると、ホーム画面に入れます。
ワークスペースを作成します
Dockerテンプレートを選択し、Docker Containerをプロバイダーとしてワークスペースを作成できます。
Docker Containerのところ、Use templateボタンを押下
そして、Create templateを押下すると、プロビジョニングが開始される
プロビジョニングが完了したと、TemplatesにDocker Containersというテンプレートが表示されます。
そして、Create Workspaceを押下
そして、ワークスペースのDockerイメージをビルドされる:
すべて完了したら、ワークスペースのプレビュー画面が表示される:
ワークスペースに接続するためのオプションから選択すると、こちらは code-server 選択し、WebバージョンのVSCodeが開いてきました。
Coder上、Templatesのところを開いて、ワークスペースリストが表示される
Source Codeのタブに遷移して、main.tfというファイルにEditを押下する
今出てきた画面だと、Terraform(HCL)のソースコードです。
Terraformの基本的な構文について説明しましょう。コードを見ながら、主要な部分を解説します。
ブロック名 "リソース名" "識別子" {
設定項目 = 値
}
# プロバイダーの設定
terraform {
required_providers {
プロバイダー名 = {
source = "ソース/プロバイダー"
}
}
}
# 変数の定義
variable "変数名" {
type = string # 型の指定
default = "デフォルト値"
description = "説明"
}
# ローカル変数
locals {
変数名 = 値
}
# リソースの定義
resource "タイプ" "名前" {
設定項目 = 値
}
# 文字列補間
name = "${var.環境名}-instance"
# 条件式
value = 条件 ? 真の場合の値 : 偽の場合の値
# データ参照
data.データソース名.識別子.属性
ベーシック
# コンテナのリソースを追加
resource "docker_container" "custom_app" {
name = "my-custom-app"
image = "nginx:latest"
ports {
internal = 80
external = 8080
}
}
# 環境変数の追加
variable "app_environment" {
type = string
default = "development"
}
# メタデータの追加
metadata {
display_name = "Custom Metric"
key = "custom_metric"
script = "echo 'Custom metric value'"
interval = 30
timeout = 1
}
コンテナの設定変更
# メモリとCPUの制限を追加
resource "docker_container" "workspace" {
count = data.coder_workspace.me.start_count
image = "codercom/enterprise-base:ubuntu"
name = "coder-${data.coder_workspace_owner.me.name}-${lower(data.coder_workspace.me.name)}"
# リソース制限の追加
cpu_shares = 1024 # CPU共有の相対値
memory = 2048 # メモリ制限(MB)
# ヘルスチェックの追加
healthcheck {
test = ["CMD", "curl", "-f", "http://localhost:13337/healthz"]
interval = "30s"
timeout = "10s"
retries = 3
}
# 追加のマウントポイント
volumes {
container_path = "/workspace"
host_path = "/path/to/workspace"
read_only = false
}
# ネットワーク設定
networks_advanced {
name = "development-network"
}
# 環境変数の拡張
env = [
"CODER_AGENT_TOKEN=${coder_agent.main.token}",
"ENVIRONMENT=development",
"DEBUG=true"
]
# 既存の設定はそのまま維持
host {
host = "host.docker.internal"
ip = "host-gateway"
}
# 既存のラベル設定を維持しつつ、新しいラベルを追加
labels {
label = "coder.owner"
value = data.coder_workspace_owner.me.name
}
labels {
label = "environment"
value = "development"
}
labels {
label = "project"
value = "coder-workspace"
}
}
新しいアプリケーションの追加
# Jupyterノートブックの追加
resource "coder_app" "jupyter" {
agent_id = coder_agent.main.id
slug = "jupyter"
display_name = "Jupyter Notebook"
url = "http://localhost:8888"
icon = "/icon/jupyter.svg"
subdomain = false
share = "owner"
healthcheck {
url = "http://localhost:8888/api/health"
interval = 5
threshold = 6
}
}
# Jupyterのインストールスクリプトをagentの起動スクリプトに追加
resource "coder_agent" "main" {
# 既存の設定を維持
startup_script = <<-EOT
set -e
# 既存のcode-serverのインストールと設定
curl -fsSL https://code-server.dev/install.sh | sh -s -- --method=standalone --prefix=/tmp/code-server
/tmp/code-server/bin/code-server --auth none --port 13337 >/tmp/code-server.log 2>&1 &
# Jupyterのインストールと設定
pip3 install jupyter
jupyter notebook --ip=0.0.0.0 --port=8888 --no-browser --NotebookApp.token='' --NotebookApp.password='' &
EOT
}
モニタリング設定の変更
# カスタムメタデータの追加
resource "coder_agent" "main" {
# 既存のメタデータを維持しつつ、新しいメタデータを追加
metadata {
display_name = "Network I/O"
key = "8_network_io"
script = <
ストレージ設定のカスタマイズ
# 追加のボリューム設定
resource "docker_volume" "workspace_data" {
name = "coder-${data.coder_workspace.me.id}-data"
# バックアップドライバーの設定
driver = "local"
driver_opts = {
type = "none"
device = "/path/to/backup/location"
o = "bind"
}
# ラベル設定
labels {
label = "coder.owner"
value = data.coder_workspace_owner.me.name
}
labels {
label = "coder.owner_id"
value = data.coder_workspace_owner.me.id
}
labels {
label = "coder.workspace_id"
value = data.coder_workspace.me.id
}
labels {
label = "backup.enabled"
value = "true"
}
# ライフサイクル設定
lifecycle {
prevent_destroy = true
ignore_changes = [driver_opts]
}
}
# 永続的なキャッシュボリューム
resource "docker_volume" "workspace_cache" {
name = "coder-${data.coder_workspace.me.id}-cache"
labels {
label = "coder.owner"
value = data.coder_workspace_owner.me.name
}
labels {
label = "coder.type"
value = "cache"
}
}
# コンテナにボリュームをマウント
resource "docker_container" "workspace" {
# 既存の設定に加えて、新しいボリュームをマウント
volumes {
container_path = "/data"
volume_name = docker_volume.workspace_data.name
read_only = false
}
volumes {
container_path = "/cache"
volume_name = docker_volume.workspace_cache.name
read_only = false
}
}