OCI無料枠でWordPress+GitLabをTerraform+Ansibleで全自動構築した話
はじめに
クラウドインフラの勉強をしたいと思い、OCI(Oracle Cloud Infrastructure)の Always Free 枠を使って WordPress と GitLab を構築してみた。ただ手動で作るだけでなく、Terraform と Ansible を使って「コードで再現できる環境」を目指した。
最終的に terraform apply と ansible-playbook site.yml の2コマンドで全環境が再現できる状態になった。しかも実質ドメイン代(年約1,600円)だけで動いている。
構成概要
インターネット
↓
Cloudflare(DNS・CDN・SSL)
↓
Internet Gateway
↓
[Public Subnet]
Bastion Host(x86 Micro / Nginx リバースプロキシ)
↓
[Private Subnet]
Main Server(ARM A1 Flex / Docker)
├── WordPress + MySQL(docker-compose)
└── GitLab CE(docker-compose)
使用リソース
| リソース | スペック | コスト |
|---|---|---|
| Bastion(x86) | VM.Standard.E2.1.Micro / 1コア / 1GB | 無料 |
| Main(ARM) | VM.Standard.A1.Flex / 4コア / 24GB / 200GB | 無料 |
| VCN・Gateway・Security List | - | 無料 |
| Cloudflare DNS・CDN・SSL | - | 無料 |
| Let's Encrypt 証明書 | - | 無料 |
| ドメイン(schift-lab.com) | Cloudflare Registrar | $10.46/年 |
ディレクトリ構成
~/schift-lab/
├── terraform/
│ ├── provider.tf
│ ├── variables.tf
│ ├── network.tf
│ ├── security.tf
│ ├── bastion.tf
│ ├── instance.tf
│ └── outputs.tf
└── ansible/
├── ansible.cfg
├── inventory.ini
├── site.yml
└── roles/
├── bastion/
│ ├── tasks/main.yml
│ ├── handlers/main.yml
│ └── templates/
│ ├── schift-lab.conf.j2
│ └── gitlab.conf.j2
└── main/
└── tasks/main.yml
Terraform でインフラを構築する
provider.tf
terraform {
required_providers {
oci = {
source = "oracle/oci"
version = "~> 6.0"
}
}
}
provider "oci" {
tenancy_ocid = var.tenancy_ocid
region = var.region
}
OCI Cloud Shell を使えば認証設定が不要。auth = "CloudShellAuth" などを書かなくても自動で認証が通る。
network.tf(抜粋)
resource "oci_core_vcn" "main" {
compartment_id = var.tenancy_ocid
cidr_block = "10.0.0.0/16"
display_name = "schift-lab-vcn"
}
resource "oci_core_subnet" "private" {
compartment_id = var.tenancy_ocid
vcn_id = oci_core_vcn.main.id
cidr_block = "10.0.2.0/24"
display_name = "schift-lab-private-subnet"
route_table_id = oci_core_route_table.private.id
security_list_ids = [oci_core_security_list.private.id]
prohibit_public_ip_on_vnic = true
}
Private Subnet に prohibit_public_ip_on_vnic = true を設定することで Main サーバーにパブリック IP が付かない。
instance.tf(Main サーバー)
resource "oci_core_instance" "main" {
compartment_id = var.tenancy_ocid
availability_domain = var.availability_domain
shape = "VM.Standard.A1.Flex"
display_name = "schift-lab-main"
shape_config {
ocpus = 4
memory_in_gbs = 24
}
source_details {
source_type = "image"
source_id = var.ubuntu_image_id_arm
boot_volume_size_in_gbs = 200
}
create_vnic_details {
subnet_id = oci_core_subnet.private.id
assign_public_ip = false
}
metadata = {
ssh_authorized_keys = trimspace(file(pathexpand("~/.ssh/id_rsa.pub")))
}
}
Ansible で環境を構築する
Bastion の設定(roles/bastion/tasks/main.yml 抜粋)
- name: Install Nginx
apt:
name: nginx
state: present
update_cache: yes
become: yes
- name: Allow port 80
iptables:
chain: INPUT
protocol: tcp
destination_port: 80
jump: ACCEPT
rule_num: 5
action: insert
become: yes
- name: Save iptables
shell: iptables-save > /etc/iptables/rules.v4
become: yes
Main の設定(roles/main/tasks/main.yml 抜粋)
- name: Deploy WordPress docker-compose
copy:
dest: /srv/wordpress/docker-compose.yml
content: |
services:
wordpress:
image: wordpress:latest
ports:
- "80:80"
environment:
WORDPRESS_DB_HOST: db
WORDPRESS_DB_USER: wp
WORDPRESS_DB_PASSWORD: secret
WORDPRESS_DB_NAME: wordpress
volumes:
- wp_data:/var/www/html
restart: always
db:
image: mysql:8.0
...
ハマったポイント
1. OCI CLI から CannotParseRequest が出続ける
Terraform の terraform apply でインスタンス作成が 400-CannotParseRequest で失敗し続けた。原因は最後まで特定できなかったが、コンソールから手動でインスタンスを作成して terraform import で取り込む方法で回避した。
terraform import oci_core_instance.bastion <OCID>
2. availability_domain の値が違った
OCI CLI で取得した値が BByO:AP-TOKYO-1-AD-1 なのに、コンソールの表示から reBByO:AP-TOKYO-1-AD-1 と誤って設定してしまい、インスタンスが再作成されようとした。
# 正しい取得方法
oci iam availability-domain list --compartment-id $OCI_TENANCY --query 'data[0].name' --raw-output
3. iptables で 80/443 番が閉じていた
OCI の Ubuntu イメージにはデフォルトで iptables のルールが設定されており、22番以外が REJECT されていた。Security List を開けるだけでは不十分で、OS 側の iptables にも穴を開ける必要があった。
sudo iptables -I INPUT 5 -p tcp --dport 80 -j ACCEPT
sudo iptables -I INPUT 6 -p tcp --dport 443 -j ACCEPT
sudo iptables-save | sudo tee /etc/iptables/rules.v4
4. VCN が2つ作られてしまった
手動でインスタンスを作成するときに誤って別の VCN を使ってしまい、Bastion と Main が異なる VCN に配置されてしまった。結果として Bastion から Main に SSH できない状態になった。terraform destroy で全部消して作り直した。
5. SSH エージェント転送
Cloud Shell では毎回 ssh-agent を起動する必要がある。.bashrc に追加しておくと便利。
if [ -z "$SSH_AUTH_SOCK" ]; then
eval $(ssh-agent -s) > /dev/null
ssh-add ~/.ssh/id_rsa 2>/dev/null
fi
実行手順まとめ
# 1. SSH キー生成(Cloud Shell)
ssh-keygen -t rsa -b 4096 -C "schift-lab"
# 2. Terraform でインフラ構築
cd ~/schift-lab/terraform
terraform init
terraform plan
terraform apply
# 3. Ansible で環境構築
cd ~/schift-lab/ansible
ansible-playbook site.yml
この3ステップで以下が自動的に構築される。
- VCN・サブネット・Gateway・Security List
- Bastion(Nginx・certbot・iptables設定済み)
- Main(Docker・WordPress・GitLab起動済み)
まとめ
OCI の Always Free 枠は思った以上に強力で、ARM の A1 Flex は4コア/24GB まで無料で使える。WordPress と GitLab を同じサーバーで Docker で動かしても十分なスペックがある。
Terraform と Ansible でコード化しておくことで、環境が壊れても terraform destroy → terraform apply → ansible-playbook site.yml で復元できる。これが IaC の醍醐味だと実感できた。
コードは GitHub で管理している。