Skip to content

Commit dd1b3a7

Browse files
Copilotlonegunmanb
andauthored
scaffold Azure prod-ready scenario; flag miniblue gaps for review
Agent-Logs-Url: https://github.com/lonegunmanb/terraform-tutorial/sessions/38089dd8-33e9-48f4-9db1-45ce5fced9ff Co-authored-by: lonegunmanb <2233414+lonegunmanb@users.noreply.github.com>
1 parent 9b9e22d commit dd1b3a7

56 files changed

Lines changed: 4295 additions & 2 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

docs/terraform-production-ready-code.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -367,4 +367,10 @@ module "app" {
367367
3. **引入社区模块**:用 `terraform-aws-modules/s3-bucket` 替换自制存储模块,接口不变
368368
4. **内置防护 + 版本固定**:加入 validation、precondition、postcondition 和版本约束,让模块更健壮
369369

370-
<KillercodaEmbed src="https://killercoda.com/lonegunman-terraform-tutorial/course/terraform-tutorial/terraform-production-ready" title="生产就绪代码:从大泥球到模块化" />
370+
<KillercodaEmbed src="https://killercoda.com/lonegunman-terraform-tutorial/course/terraform-tutorial/terraform-production-ready" title="生产就绪代码:从大泥球到模块化(AWS / LocalStack 版)" />
371+
372+
<KillercodaEmbed
373+
src="https://killercoda.com/lonegunman-terraform-tutorial/course/terraform-tutorial/terraform-production-ready-azure"
374+
title="生产就绪代码:从大泥球到模块化(Azure / miniblue 版)"
375+
desc="点击下方按钮在新标签页中打开 Azure 版 Killercoda 实验环境,预装了 Terraform + Terragrunt + miniblue(Azure 本地模拟器)。资源映射:VPC→VNet、ALB→Load Balancer、EC2→Linux VM、DynamoDB→Cosmos DB、S3→Storage Account、IAM Role→Managed Identity、Secrets Manager→Key Vault、SSM Parameter→App Configuration;五个步骤的拆模块/moved/removed/Terragrunt 流程与 AWS 版完全一致。"
376+
/>

terraform-tutorial/structure.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@
5050
{ "path": "terraform-tool-terraform-docs" },
5151
{ "path": "terraform-tool-checkov" },
5252
{ "path": "terraform-tool-conftest" },
53-
{ "path": "terraform-production-ready" }
53+
{ "path": "terraform-production-ready" },
54+
{ "path": "terraform-production-ready-azure" }
5455
]
5556
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
services:
2+
miniblue:
3+
image: ghcr.io/lonegunmanb/miniblue:sha-2fead35
4+
ports:
5+
- "4566:4566"
6+
- "4567:4567"
7+
deploy:
8+
resources:
9+
limits:
10+
memory: 512M
Lines changed: 205 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,205 @@
1+
#!/bin/bash
2+
# ─────────────────────────────────────────────────────────
3+
# setup-common.sh — shared setup functions for Killercoda scenarios
4+
#
5+
# This file is the SINGLE SOURCE OF TRUTH for common setup logic.
6+
# It is copied into each scenario's assets/ directory by:
7+
# npm run sync-setup (or automatically via prebuild)
8+
#
9+
# Usage in background.sh:
10+
# source /root/setup-common.sh
11+
# install_terraform
12+
# install_awscli # optional — AWS CLI v2 + awslocal wrapper
13+
# install_tflint # optional — only in scenarios that need it
14+
# start_localstack
15+
# install_theia_plugin
16+
# finish_setup
17+
# ─────────────────────────────────────────────────────────
18+
19+
TERRAFORM_VERSION="${TERRAFORM_VERSION:-1.14.8}"
20+
TFLINT_VERSION="${TFLINT_VERSION:-v0.61.0}"
21+
TERRAGRUNT_VERSION="${TERRAGRUNT_VERSION:-0.77.5}"
22+
# Note: the miniblue container image tag is pinned in scripts/miniblue-image.mjs
23+
# and propagated into every docker-compose.yml by `npm run sync-miniblue`.
24+
# There is no shell-side miniblue version variable — start_miniblue just runs
25+
# `docker compose up -d` against the pinned compose file.
26+
27+
install_terraform() {
28+
if ! command -v unzip > /dev/null 2>&1; then
29+
apt-get update -qq && apt-get install -y -qq unzip > /dev/null 2>&1
30+
fi
31+
32+
# Install Docker Compose v2 plugin (binary download — apt package not available on Killercoda)
33+
if ! docker compose version > /dev/null 2>&1; then
34+
mkdir -p /usr/local/lib/docker/cli-plugins
35+
curl --connect-timeout 10 --max-time 120 -fsSL \
36+
"https://github.com/docker/compose/releases/latest/download/docker-compose-linux-x86_64" \
37+
-o /usr/local/lib/docker/cli-plugins/docker-compose
38+
chmod +x /usr/local/lib/docker/cli-plugins/docker-compose
39+
fi
40+
41+
curl --connect-timeout 10 --max-time 120 -fsSL \
42+
"https://releases.hashicorp.com/terraform/${TERRAFORM_VERSION}/terraform_${TERRAFORM_VERSION}_linux_amd64.zip" \
43+
-o /tmp/terraform.zip \
44+
&& unzip -o -q /tmp/terraform.zip -d /usr/local/bin/ \
45+
&& chmod +x /usr/local/bin/terraform \
46+
&& rm -f /tmp/terraform.zip
47+
48+
terraform version || echo "WARNING: terraform install failed"
49+
}
50+
51+
install_tflint() {
52+
curl --connect-timeout 10 --max-time 120 -fsSL \
53+
"https://github.com/terraform-linters/tflint/releases/download/${TFLINT_VERSION}/tflint_linux_amd64.zip" \
54+
-o /tmp/tflint.zip \
55+
&& unzip -o -q /tmp/tflint.zip -d /usr/local/bin/ \
56+
&& chmod +x /usr/local/bin/tflint \
57+
&& rm -f /tmp/tflint.zip
58+
59+
tflint --version || echo "WARNING: tflint install failed"
60+
}
61+
62+
install_terragrunt() {
63+
curl --connect-timeout 10 --max-time 120 -fsSL \
64+
"https://github.com/gruntwork-io/terragrunt/releases/download/v${TERRAGRUNT_VERSION}/terragrunt_linux_amd64" \
65+
-o /usr/local/bin/terragrunt \
66+
&& chmod +x /usr/local/bin/terragrunt
67+
68+
terragrunt --version || echo "WARNING: terragrunt install failed"
69+
}
70+
71+
install_awscli() {
72+
# Install AWS CLI v2 (official binary)
73+
curl --connect-timeout 10 --max-time 120 -fsSL \
74+
"https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" \
75+
-o /tmp/awscliv2.zip \
76+
&& unzip -o -q /tmp/awscliv2.zip -d /tmp/ \
77+
&& /tmp/aws/install --update > /dev/null 2>&1 \
78+
&& rm -rf /tmp/awscliv2.zip /tmp/aws
79+
80+
aws --version || echo "WARNING: awscli install failed"
81+
82+
# Disable AWS CLI pager globally so output prints directly
83+
mkdir -p /root/.aws
84+
cat > /root/.aws/config <<'AWSCFG'
85+
[default]
86+
region = us-east-1
87+
output = json
88+
cli_pager =
89+
AWSCFG
90+
91+
# Install awscli-local (provides the 'awslocal' command)
92+
pip3 install --break-system-packages awscli-local > /dev/null 2>&1 \
93+
|| {
94+
# Fallback: create a shell wrapper if pip fails
95+
cat > /usr/local/bin/awslocal <<'WRAPPER'
96+
#!/bin/bash
97+
export AWS_PAGER=""
98+
exec aws --endpoint-url=http://localhost:4566 --region us-east-1 "$@"
99+
WRAPPER
100+
chmod +x /usr/local/bin/awslocal
101+
}
102+
103+
awslocal --version || echo "WARNING: awslocal install failed"
104+
}
105+
106+
start_localstack() {
107+
cd /root/workspace
108+
docker compose up -d
109+
110+
echo "Waiting for LocalStack to be ready..."
111+
for i in $(seq 1 60); do
112+
if curl -sf http://localhost:4566/_localstack/health > /dev/null 2>&1; then
113+
echo "LocalStack is ready."
114+
return 0
115+
fi
116+
sleep 2
117+
done
118+
echo "WARNING: LocalStack did not become healthy within 120 seconds"
119+
docker compose logs
120+
}
121+
122+
start_miniblue() {
123+
cd /root/workspace
124+
mkdir -p /root/.miniblue
125+
docker compose up -d
126+
127+
echo "Waiting for miniblue to be ready..."
128+
for i in $(seq 1 60); do
129+
if curl -sf http://localhost:4566/health > /dev/null 2>&1; then
130+
echo "miniblue is ready."
131+
# Trigger an HTTPS request so miniblue generates its self-signed cert.
132+
curl -sk https://localhost:4567/health > /dev/null 2>&1 || true
133+
134+
# Locate cert inside the container and copy to host.
135+
# The miniblue image is distroless (no shell), so we can't `docker exec`
136+
# to probe — `docker cp` itself is sufficient and silently fails on
137+
# missing paths. Try known paths in order.
138+
local cid
139+
cid=$(docker compose ps -q miniblue 2>/dev/null)
140+
for j in $(seq 1 30); do
141+
if [ -n "$cid" ]; then
142+
for p in /home/nonroot/.miniblue/cert.pem /root/.miniblue/cert.pem /app/.miniblue/cert.pem; do
143+
if docker cp "$cid:$p" /root/.miniblue/cert.pem 2>/dev/null; then
144+
break 2
145+
fi
146+
done
147+
fi
148+
sleep 1
149+
done
150+
151+
if [ ! -f /root/.miniblue/cert.pem ]; then
152+
echo "WARNING: failed to copy miniblue cert.pem out of container"
153+
else
154+
chmod 644 /root/.miniblue/cert.pem
155+
# Install the cert into the system CA trust store so Go-based tools
156+
# (terraform, azurerm provider) trust https://localhost:4567 WITHOUT
157+
# needing SSL_CERT_FILE. This matters because Killercoda terminals are
158+
# opened BEFORE background.sh runs, so the export appended to ~/.bashrc
159+
# below does not affect the user's existing shell.
160+
if command -v update-ca-certificates > /dev/null 2>&1; then
161+
mkdir -p /usr/local/share/ca-certificates
162+
cp /root/.miniblue/cert.pem /usr/local/share/ca-certificates/miniblue.crt
163+
update-ca-certificates > /dev/null 2>&1 || true
164+
fi
165+
fi
166+
167+
# Make SSL_CERT_FILE available for all interactive shells (belt-and-braces;
168+
# the system trust store above is the primary mechanism).
169+
cat > /etc/profile.d/miniblue.sh <<'PROF'
170+
export SSL_CERT_FILE=/root/.miniblue/cert.pem
171+
PROF
172+
chmod +x /etc/profile.d/miniblue.sh
173+
# Killercoda terminals are non-login interactive shells — they only source
174+
# ~/.bashrc, not /etc/profile.d/*. Append the export there too (idempotent).
175+
if ! grep -q 'SSL_CERT_FILE=/root/.miniblue/cert.pem' /root/.bashrc 2>/dev/null; then
176+
echo 'export SSL_CERT_FILE=/root/.miniblue/cert.pem' >> /root/.bashrc
177+
fi
178+
export SSL_CERT_FILE=/root/.miniblue/cert.pem
179+
return 0
180+
fi
181+
sleep 2
182+
done
183+
echo "WARNING: miniblue did not become healthy within 120 seconds"
184+
docker compose logs
185+
}
186+
187+
finish_setup() {
188+
touch /tmp/.setup-done
189+
}
190+
191+
install_azlocal() {
192+
# azlocal is a standalone Go CLI bundled inside the miniblue image at /azlocal
193+
# (analogous to awslocal for LocalStack). It uses HTTP on port 4566 and needs
194+
# no certificate or az CLI. Requires miniblue to be running.
195+
local cid
196+
cid=$(docker compose ps -q miniblue 2>/dev/null)
197+
if [ -z "$cid" ]; then
198+
cid=$(docker ps -q --filter "name=miniblue" | head -1)
199+
fi
200+
if [ -n "$cid" ]; then
201+
docker cp "$cid:/azlocal" /usr/local/bin/azlocal 2>/dev/null \
202+
&& chmod +x /usr/local/bin/azlocal
203+
fi
204+
azlocal --help > /dev/null 2>&1 || echo "WARNING: azlocal install failed"
205+
}

0 commit comments

Comments
 (0)