86 lines
2.9 KiB
YAML
86 lines
2.9 KiB
YAML
#cloud-config
|
|
# First-boot bootstrap: base packages + Docker + git. App layer via ansible.
|
|
|
|
package_update: true
|
|
packages:
|
|
- apt-transport-https
|
|
- ca-certificates
|
|
- curl
|
|
- gnupg
|
|
- lsb-release
|
|
- jq
|
|
- unzip
|
|
- git
|
|
|
|
write_files:
|
|
# Docker installation
|
|
- path: /tmp/install-docker.sh
|
|
permissions: "0755"
|
|
content: |
|
|
#!/bin/bash
|
|
set -euo pipefail
|
|
curl -fsSL https://get.docker.com -o /tmp/get-docker.sh
|
|
sh /tmp/get-docker.sh
|
|
systemctl enable docker
|
|
systemctl start docker
|
|
usermod -aG docker ubuntu
|
|
|
|
# Docker daemon config (log rotation)
|
|
- path: /etc/docker/daemon.json
|
|
content: |
|
|
{
|
|
"log-driver": "json-file",
|
|
"log-opts": {
|
|
"max-size": "10m",
|
|
"max-file": "3"
|
|
},
|
|
"storage-driver": "overlay2"
|
|
}
|
|
|
|
# Encrypted-at-rest data volume setup (runs BEFORE Docker is installed).
|
|
# Graceful no-op when no volume is attached (data_volume_size_gb = 0 default
|
|
# for aibook-fun stateless marketing site).
|
|
- path: /tmp/setup-data-volume.sh
|
|
permissions: "0755"
|
|
content: |
|
|
#!/bin/bash
|
|
set -euo pipefail
|
|
DEV="/dev/disk/by-id/scsi-0DO_Volume_aibook-fun-data"
|
|
MNT="/mnt/${project_name}_data"
|
|
for i in $(seq 1 24); do
|
|
[ -e "$DEV" ] && break
|
|
sleep 5
|
|
done
|
|
if [ ! -e "$DEV" ]; then
|
|
echo "no data volume attached after 120s - using droplet local disk (stateless mode)"
|
|
exit 0
|
|
fi
|
|
blkid "$DEV" >/dev/null 2>&1 || mkfs.ext4 -q "$DEV"
|
|
mkdir -p "$MNT"
|
|
grep -q "scsi-0DO_Volume_aibook-fun-data" /etc/fstab || \
|
|
echo "$DEV $MNT ext4 defaults,noatime,nofail,discard 0 2" >> /etc/fstab
|
|
mountpoint -q "$MNT" || mount "$MNT"
|
|
mkdir -p "$MNT/docker"
|
|
jq --arg dr "$MNT/docker" '. + {"data-root": $dr}' /etc/docker/daemon.json > /tmp/daemon.json.new
|
|
mv /tmp/daemon.json.new /etc/docker/daemon.json
|
|
mkdir -p /opt/${project_name}
|
|
echo "data volume mounted at $MNT (docker data-root relocated)"
|
|
|
|
runcmd:
|
|
# Data volume setup only when a block volume is attached
|
|
- 'bash -c "[ -e /dev/disk/by-id/scsi-0DO_Volume_aibook-fun-data ] && bash /tmp/setup-data-volume.sh || echo no-data-volume"'
|
|
- [bash, /tmp/install-docker.sh]
|
|
- [systemctl, restart, docker]
|
|
# Ensure the app dir exists for ansible to land the compose + Caddyfile
|
|
- [mkdir, -p, /opt/${project_name}]
|
|
# Marker so ansible/deploy.yml can confirm the host is ready
|
|
- [touch, /opt/${project_name}/.bootstrap-complete]
|
|
# Enable automatic security updates
|
|
- dpkg-reconfigure -plow unattended-upgrades
|
|
|
|
final_message: |
|
|
aibook-fun bootstrap complete. Next step from the operator workstation:
|
|
ansible-playbook aibook-fun/ansible/deploy.yml -i 'root@<this-droplet-ip>,'
|
|
Ansible will clone the repo, build the Docker image locally on this droplet,
|
|
and bring up the compose stack. Site served at https://aibook.fun.
|