cloud-init-coder
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseCloud-Init Coder
Cloud-Init 配置编写指南
Overview
概述
Cloud-init is the industry standard for cross-platform cloud instance initialization. It runs on first boot to configure users, packages, files, and services before the instance becomes available.
Cloud-init是跨平台云实例初始化的行业标准。它会在实例首次启动时运行,在实例可用之前配置用户、软件包、文件和服务。
Core Format
核心格式
Cloud-init configs start with :
#cloud-configyaml
#cloud-config
package_update: true
packages:
- nginx
- docker.iocloud-init配置文件以开头:
#cloud-configyaml
#cloud-config
package_update: true
packages:
- nginx
- docker.ioUser Management
用户管理
Create Deploy User
创建部署用户
yaml
#cloud-config
users:
- name: deploy
groups: docker, sudo
sudo: ALL=(ALL) NOPASSWD:ALL
shell: /bin/bash
ssh_authorized_keys:
- ssh-ed25519 AAAA... deploy@example.comyaml
#cloud-config
users:
- name: deploy
groups: docker, sudo
sudo: ALL=(ALL) NOPASSWD:ALL
shell: /bin/bash
ssh_authorized_keys:
- ssh-ed25519 AAAA... deploy@example.comMultiple Users
多用户配置
yaml
#cloud-config
users:
- default # Keep cloud provider's default user
- name: deploy
groups: docker
sudo: ALL=(ALL) NOPASSWD:ALL
shell: /bin/bash
ssh_authorized_keys:
- ssh-ed25519 AAAA... key1
- name: monitoring
groups: adm
shell: /bin/bash
ssh_authorized_keys:
- ssh-ed25519 AAAA... monitoring-keyyaml
#cloud-config
users:
- default # 保留云服务商的默认用户
- name: deploy
groups: docker
sudo: ALL=(ALL) NOPASSWD:ALL
shell: /bin/bash
ssh_authorized_keys:
- ssh-ed25519 AAAA... key1
- name: monitoring
groups: adm
shell: /bin/bash
ssh_authorized_keys:
- ssh-ed25519 AAAA... monitoring-keyPackage Installation
软件包安装
Basic Packages
基础软件包
yaml
#cloud-config
package_update: true
package_upgrade: true
packages:
- docker.io
- docker-compose-plugin
- nginx
- certbot
- python3-certbot-nginx
- fail2ban
- ufwyaml
#cloud-config
package_update: true
package_upgrade: true
packages:
- docker.io
- docker-compose-plugin
- nginx
- certbot
- python3-certbot-nginx
- fail2ban
- ufwFrom Custom Repositories
从自定义仓库安装
yaml
#cloud-config
apt:
sources:
docker:
source: "deb [arch=amd64] https://download.docker.com/linux/ubuntu $RELEASE stable"
keyid: 9DC858229FC7DD38854AE2D88D81803C0EBFCD88
packages:
- docker-ce
- docker-ce-cli
- containerd.ioyaml
#cloud-config
apt:
sources:
docker:
source: "deb [arch=amd64] https://download.docker.com/linux/ubuntu $RELEASE stable"
keyid: 9DC858229FC7DD38854AE2D88D81803C0EBFCD88
packages:
- docker-ce
- docker-ce-cli
- containerd.ioSSH Hardening
SSH 加固
Declarative SSH Lockdown
声明式SSH锁定
Prefer declarative over runcmd sed commands:
ssh_pwauth: falseyaml
#cloud-config
ssh_pwauth: false # Disable password auth at cloud-init level
runcmd:
# Additional hardening via sshd_config
- sed -i 's/^#\?PermitRootLogin.*/PermitRootLogin prohibit-password/' /etc/ssh/sshd_config
- systemctl restart sshd优先使用声明式的而非runcmd中的sed命令:
ssh_pwauth: falseyaml
#cloud-config
ssh_pwauth: false # 在cloud-init层面禁用密码认证
runcmd:
# 通过sshd_config进行额外加固
- sed -i 's/^#\?PermitRootLogin.*/PermitRootLogin prohibit-password/' /etc/ssh/sshd_config
- systemctl restart sshdFull SSH Hardening
完整SSH加固配置
yaml
#cloud-config
ssh_pwauth: false # Declarative - cleaner than sed
runcmd:
# Disable root login (or use prohibit-password for key-only root)
- sed -i 's/^#\?PermitRootLogin.*/PermitRootLogin no/' /etc/ssh/sshd_config
- sed -i 's/^PermitRootLogin yes/PermitRootLogin no/' /etc/ssh/sshd_config
# Disable password authentication (backup for ssh_pwauth)
- sed -i 's/^#\?PasswordAuthentication.*/PasswordAuthentication no/' /etc/ssh/sshd_config
# Increase keepalive for stable connections
- sed -i 's/^#\?ClientAliveInterval.*/ClientAliveInterval 60/' /etc/ssh/sshd_config
- sed -i 's/^#\?ClientAliveCountMax.*/ClientAliveCountMax 10/' /etc/ssh/sshd_config
# Restart SSH
- systemctl restart sshdyaml
#cloud-config
ssh_pwauth: false # 声明式配置 - 比sed更简洁
runcmd:
# 禁用root登录(或使用prohibit-password仅允许密钥登录root)
- sed -i 's/^#\?PermitRootLogin.*/PermitRootLogin no/' /etc/ssh/sshd_config
- sed -i 's/^PermitRootLogin yes/PermitRootLogin no/' /etc/ssh/sshd_config
# 禁用密码认证(作为ssh_pwauth的备份)
- sed -i 's/^#\?PasswordAuthentication.*/PasswordAuthentication no/' /etc/ssh/sshd_config
# 增加保活时间以维持稳定连接
- sed -i 's/^#\?ClientAliveInterval.*/ClientAliveInterval 60/' /etc/ssh/sshd_config
- sed -i 's/^#\?ClientAliveCountMax.*/ClientAliveCountMax 10/' /etc/ssh/sshd_config
# 重启SSH服务
- systemctl restart sshdDocker Setup
Docker 配置
Docker with Compose
Docker 与 Compose 配置
yaml
#cloud-config
package_update: true
packages:
- docker.io
- docker-compose-plugin
groups:
- docker
users:
- name: deploy
groups: docker
sudo: ALL=(ALL) NOPASSWD:ALL
shell: /bin/bash
ssh_authorized_keys:
- ssh-ed25519 AAAA...
runcmd:
- systemctl enable --now docker
- usermod -aG docker deployyaml
#cloud-config
package_update: true
packages:
- docker.io
- docker-compose-plugin
groups:
- docker
users:
- name: deploy
groups: docker
sudo: ALL=(ALL) NOPASSWD:ALL
shell: /bin/bash
ssh_authorized_keys:
- ssh-ed25519 AAAA...
runcmd:
- systemctl enable --now docker
- usermod -aG docker deployDocker with Custom Daemon Config
自定义Docker守护进程配置
yaml
#cloud-config
write_files:
- path: /etc/docker/daemon.json
content: |
{
"log-driver": "json-file",
"log-opts": {
"max-size": "10m",
"max-file": "3"
},
"storage-driver": "overlay2"
}
runcmd:
- systemctl enable --now dockeryaml
#cloud-config
write_files:
- path: /etc/docker/daemon.json
content: |
{
"log-driver": "json-file",
"log-opts": {
"max-size": "10m",
"max-file": "3"
},
"storage-driver": "overlay2"
}
runcmd:
- systemctl enable --now dockerFile Creation
文件创建
Write Configuration Files
编写配置文件
yaml
#cloud-config
write_files:
- path: /etc/nginx/sites-available/app
content: |
server {
listen 80;
server_name example.com;
location / {
proxy_pass http://127.0.0.1:3000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
owner: root:root
permissions: '0644'
- path: /opt/app/.env
content: |
RAILS_ENV=production
PORT=3000
owner: deploy:deploy
permissions: '0600'yaml
#cloud-config
write_files:
- path: /etc/nginx/sites-available/app
content: |
server {
listen 80;
server_name example.com;
location / {
proxy_pass http://127.0.0.1:3000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
owner: root:root
permissions: '0644'
- path: /opt/app/.env
content: |
RAILS_ENV=production
PORT=3000
owner: deploy:deploy
permissions: '0600'Download Files
下载文件
yaml
#cloud-config
runcmd:
- curl -fsSL https://example.com/setup.sh -o /opt/setup.sh
- chmod +x /opt/setup.sh
- /opt/setup.shyaml
#cloud-config
runcmd:
- curl -fsSL https://example.com/setup.sh -o /opt/setup.sh
- chmod +x /opt/setup.sh
- /opt/setup.shService Configuration
服务配置
Enable and Start Services
启用并启动服务
yaml
#cloud-config
runcmd:
- systemctl enable --now docker
- systemctl enable --now nginx
- systemctl enable --now fail2banyaml
#cloud-config
runcmd:
- systemctl enable --now docker
- systemctl enable --now nginx
- systemctl enable --now fail2banSystemd Service Creation
Systemd 服务创建
yaml
#cloud-config
write_files:
- path: /etc/systemd/system/myapp.service
content: |
[Unit]
Description=My Application
After=network.target docker.service
Requires=docker.service
[Service]
Type=simple
User=deploy
WorkingDirectory=/opt/app
ExecStart=/usr/bin/docker compose up
ExecStop=/usr/bin/docker compose down
Restart=always
RestartSec=10
[Install]
WantedBy=multi-user.target
runcmd:
- systemctl daemon-reload
- systemctl enable --now myappyaml
#cloud-config
write_files:
- path: /etc/systemd/system/myapp.service
content: |
[Unit]
Description=My Application
After=network.target docker.service
Requires=docker.service
[Service]
Type=simple
User=deploy
WorkingDirectory=/opt/app
ExecStart=/usr/bin/docker compose up
ExecStop=/usr/bin/docker compose down
Restart=always
RestartSec=10
[Install]
WantedBy=multi-user.target
runcmd:
- systemctl daemon-reload
- systemctl enable --now myappFirewall Configuration
防火墙配置
UFW Setup
UFW 配置
yaml
#cloud-config
packages:
- ufw
runcmd:
- ufw default deny incoming
- ufw default allow outgoing
- ufw allow ssh
- ufw allow http
- ufw allow https
- ufw --force enableyaml
#cloud-config
packages:
- ufw
runcmd:
- ufw default deny incoming
- ufw default allow outgoing
- ufw allow ssh
- ufw allow http
- ufw allow https
- ufw --force enableTerraform/OpenTofu Integration
Terraform/OpenTofu 集成
Inline User Data
内联用户数据
hcl
resource "digitalocean_droplet" "app" {
name = "app-server"
image = "ubuntu-22-04-x64"
size = "s-1vcpu-1gb"
region = "nyc1"
user_data = <<-EOT
#cloud-config
package_update: true
packages:
- docker.io
- docker-compose-plugin
users:
- name: deploy
groups: docker
sudo: ALL=(ALL) NOPASSWD:ALL
shell: /bin/bash
ssh_authorized_keys:
- ${var.deploy_ssh_key}
runcmd:
- systemctl enable --now docker
EOT
}hcl
resource "digitalocean_droplet" "app" {
name = "app-server"
image = "ubuntu-22-04-x64"
size = "s-1vcpu-1gb"
region = "nyc1"
user_data = <<-EOT
#cloud-config
package_update: true
packages:
- docker.io
- docker-compose-plugin
users:
- name: deploy
groups: docker
sudo: ALL=(ALL) NOPASSWD:ALL
shell: /bin/bash
ssh_authorized_keys:
- ${var.deploy_ssh_key}
runcmd:
- systemctl enable --now docker
EOT
}Template File
模板文件
hcl
undefinedhcl
undefinedtemplates/cloud-init.yaml
templates/cloud-init.yaml
#cloud-config
package_update: true
packages:
- docker.io users:
- name: ${username}
groups: docker
ssh_authorized_keys:
- ${ssh_key}
#cloud-config
package_update: true
packages:
- docker.io users:
- name: ${username}
groups: docker
ssh_authorized_keys:
- ${ssh_key}
main.tf
main.tf
resource "digitalocean_droplet" "app" {
user_data = templatefile("${path.module}/templates/cloud-init.yaml", {
username = var.deploy_user
ssh_key = var.deploy_ssh_key
})
}
undefinedresource "digitalocean_droplet" "app" {
user_data = templatefile("${path.module}/templates/cloud-init.yaml", {
username = var.deploy_user
ssh_key = var.deploy_ssh_key
})
}
undefinedComplete Production Example
完整生产环境示例
yaml
#cloud-config
package_update: true
package_upgrade: true
packages:
- docker.io
- docker-compose-plugin
- fail2ban
- ufw
- unattended-upgrades
groups:
- docker
users:
- name: deploy
groups: docker, sudo
sudo: ALL=(ALL) NOPASSWD:ALL
shell: /bin/bash
ssh_authorized_keys:
- ssh-ed25519 AAAA... deploy-key
write_files:
- path: /etc/docker/daemon.json
content: |
{
"log-driver": "json-file",
"log-opts": { "max-size": "10m", "max-file": "3" }
}
- path: /etc/fail2ban/jail.local
content: |
[sshd]
enabled = true
port = ssh
filter = sshd
maxretry = 3
bantime = 3600
runcmd:
# Docker
- systemctl enable --now docker
# SSH hardening
- sed -i 's/^#\?PermitRootLogin.*/PermitRootLogin no/' /etc/ssh/sshd_config
- sed -i 's/^#\?PasswordAuthentication.*/PasswordAuthentication no/' /etc/ssh/sshd_config
- sed -i 's/^#\?ClientAliveInterval.*/ClientAliveInterval 60/' /etc/ssh/sshd_config
- sed -i 's/^#\?ClientAliveCountMax.*/ClientAliveCountMax 10/' /etc/ssh/sshd_config
- systemctl restart sshd
# Firewall
- ufw default deny incoming
- ufw default allow outgoing
- ufw allow ssh
- ufw allow http
- ufw allow https
- ufw --force enable
# Fail2ban
- systemctl enable --now fail2ban
# Auto-updates
- systemctl enable --now unattended-upgrades
final_message: "Cloud-init completed after $UPTIME seconds"yaml
#cloud-config
package_update: true
package_upgrade: true
packages:
- docker.io
- docker-compose-plugin
- fail2ban
- ufw
- unattended-upgrades
groups:
- docker
users:
- name: deploy
groups: docker, sudo
sudo: ALL=(ALL) NOPASSWD:ALL
shell: /bin/bash
ssh_authorized_keys:
- ssh-ed25519 AAAA... deploy-key
write_files:
- path: /etc/docker/daemon.json
content: |
{
"log-driver": "json-file",
"log-opts": { "max-size": "10m", "max-file": "3" }
}
- path: /etc/fail2ban/jail.local
content: |
[sshd]
enabled = true
port = ssh
filter = sshd
maxretry = 3
bantime = 3600
runcmd:
# Docker
- systemctl enable --now docker
# SSH 加固
- sed -i 's/^#\?PermitRootLogin.*/PermitRootLogin no/' /etc/ssh/sshd_config
- sed -i 's/^#\?PasswordAuthentication.*/PasswordAuthentication no/' /etc/ssh/sshd_config
- sed -i 's/^#\?ClientAliveInterval.*/ClientAliveInterval 60/' /etc/ssh/sshd_config
- sed -i 's/^#\?ClientAliveCountMax.*/ClientAliveCountMax 10/' /etc/ssh/sshd_config
- systemctl restart sshd
# 防火墙
- ufw default deny incoming
- ufw default allow outgoing
- ufw allow ssh
- ufw allow http
- ufw allow https
- ufw --force enable
# Fail2ban
- systemctl enable --now fail2ban
# 自动更新
- systemctl enable --now unattended-upgrades
final_message: "Cloud-init completed after $UPTIME seconds"Server Tuning
服务器调优
Performance and Cleanup
性能优化与清理
yaml
#cloud-config
runcmd:
# Reduce swap usage (better for databases/apps with their own memory management)
- |
if ! grep -q "vm.swappiness=10" /etc/sysctl.conf; then
echo "vm.swappiness=10" >> /etc/sysctl.conf
sysctl -p
fi
# Set timezone
- timedatectl set-timezone UTC # Or: Europe/Berlin, America/New_York
# Cleanup
- apt-get autoremove -y
- apt-get cleanyaml
#cloud-config
runcmd:
# 减少swap使用(对使用自有内存管理的数据库/应用更友好)
- |
if ! grep -q "vm.swappiness=10" /etc/sysctl.conf; then
echo "vm.swappiness=10" >> /etc/sysctl.conf
sysctl -p
fi
# 设置时区
- timedatectl set-timezone UTC # 或者:Europe/Berlin, America/New_York
# 清理
- apt-get autoremove -y
- apt-get cleanSwappiness Values
Swappiness 值说明
| Value | Behavior |
|---|---|
| Only swap to avoid OOM |
| Minimal swapping (recommended for apps) |
| Default Ubuntu |
| Aggressive swapping |
| 数值 | 行为 |
|---|---|
| 仅在避免内存不足时使用swap |
| 最小化swap使用(推荐给应用服务器) |
| Ubuntu默认值 |
| 激进式swap使用 |
Debugging
调试
Check Cloud-Init Status
检查Cloud-Init状态
bash
undefinedbash
undefinedView cloud-init status
查看cloud-init状态
cloud-init status
cloud-init status
View cloud-init logs
查看cloud-init日志
cat /var/log/cloud-init.log
cat /var/log/cloud-init-output.log
cat /var/log/cloud-init.log
cat /var/log/cloud-init-output.log
Re-run cloud-init (for testing)
重新运行cloud-init(用于测试)
sudo cloud-init clean
sudo cloud-init init
undefinedsudo cloud-init clean
sudo cloud-init init
undefinedCommon Issues
常见问题
| Issue | Cause | Fix |
|---|---|---|
| YAML parse error | Indentation wrong | Use 2-space indent, validate YAML |
| User not created | Missing | Ensure |
| Packages not installed | | Set |
| SSH key rejected | Wrong key format | Use full public key string |
| Service not starting | Order dependency | Use |
| 问题 | 原因 | 解决方法 |
|---|---|---|
| YAML解析错误 | 缩进错误 | 使用2空格缩进,验证YAML格式 |
| 用户未创建 | 缺少 | 确保 |
| 软件包未安装 | | 设置 |
| SSH密钥被拒绝 | 密钥格式错误 | 使用完整的公钥字符串 |
| 服务未启动 | 依赖顺序问题 | 在systemd单元中使用 |