diff options
author | EuAndreh <eu@euandre.org> | 2019-05-26 11:51:51 -0300 |
---|---|---|
committer | EuAndreh <eu@euandre.org> | 2019-05-26 11:51:51 -0300 |
commit | da00227813b1fbeebae8c90e2122a8b73acb1af9 (patch) | |
tree | edbd087c4868d78a709b1290cf241a4a439e527e | |
parent | Add 1 git-crypt collaborator (diff) | |
download | server-da00227813b1fbeebae8c90e2122a8b73acb1af9.tar.gz server-da00227813b1fbeebae8c90e2122a8b73acb1af9.tar.xz |
Automate provisioning and deployment of VPS
In order to perform that I had to remove Terraform's =.tfstate= files from the
repository. Terraform does support "backends" for storing the state files, but I
settled for storing it on a separate repo (vps-state).
For now it solves the state management problem:
- it has history of states;
- all state files are GPG encrypted;
- there's no coordination however, but only the CI should perform a deploy in
order to avoid race conditions.
I had to add GPG and SSH keys to sr.ht to achieve that:
- SSH public key to my profile to authorize it to push to vps-state repo;
- SSH private key to the secret builds.sr.ht environment to enable push to the
repository from the pipeline;
- GPG public key to git-crypt to make it possible for the pipeline to unlock the
encrypted content;
- GPG private key to the secret builds.sr.ht environment to enable decrypting
git-crypt content from the pipeline.
In order to avoid divergent environment from local and CI, the ./provision.sh
script is ran through nix-shell.
-rw-r--r-- | .build.yml | 7 | ||||
-rw-r--r-- | TODOs.org | 4 | ||||
-rw-r--r-- | default.nix | 3 | ||||
-rwxr-xr-x | deploy.sh | 34 | ||||
-rw-r--r-- | provision.sh | 36 | ||||
-rw-r--r-- | secrets/terraform.tfstate | bin | 2243 -> 0 bytes | |||
-rw-r--r-- | secrets/terraform.tfstate.backup | bin | 2244 -> 0 bytes | |||
l--------- | terraform.tfstate | 2 | ||||
l--------- | terraform.tfstate.backup | 2 | ||||
-rw-r--r-- | vps.tf | 6 |
10 files changed, 83 insertions, 11 deletions
@@ -7,7 +7,14 @@ triggers: to: EuAndreh <ci@euandre.org> sources: - https://git.sr.ht/~euandreh/vps + - https://git.sr.ht/~euandreh/vps-state +secrets: + - b1f49116-7515-40ef-857c-42e4519b8472 + - 7084b7c7-12be-4509-8927-81ba6eeb1fc0 tasks: - tests: | cd vps/ nix-build -A test + - deploy: | + cd vps/ + nix-shell --run "bash -c ./provision.sh" @@ -18,9 +18,13 @@ We could try to share a shared volume, but that would be a consistency nightmare The other option is to always recreate everything, with downtime. The advantage is that we get actual immutable deployments with stateful storage, but there would be downtime for every deployment. This is due to the nature of most of the packaged applications being single node *only*. +There's also the IP reputation issue: recreating everything from scratch every time would lead to new droplets with new IP addresses, which is not a good thing to be changing in a server box. + A reasonable alternative would be to redeploy everything on a different node, with a different TLD, and manually check that. But that would be just like an staging environment, with all of it's downsides too. In this situation, I if go on with automating the deployment I'd rather pick the downtime option. + +I'll start with other services other than email and consider alternatives later. ** WAITING Configure DNS from Terraform * Must ** Fully deployable from code diff --git a/default.nix b/default.nix index c7c5bc4..67830e2 100644 --- a/default.nix +++ b/default.nix @@ -95,8 +95,9 @@ with pkgs.stdenv; rec { touch $out ''; }); + # Used in .build.yml to run ./provision.sh shell = mkShell rec { name = "vps-shell"; - buildInputs = [ nixfmt terraform-full ]; + buildInputs = [ terraform terraform-providers.digitalocean git-crypt ]; }; } @@ -2,22 +2,42 @@ set -Eeuo pipefail cd "${BASH_SOURCE%/*}/" -yellow "Ubuntu maintenence..." +alias ssh="ssh -i secrets/id_rsa root@$TLD" + +apt_wait() { + local i=0 + tput sc + while fuser /var/lib/apt/lists/lock >/dev/null 2>&1 ; do + case $((i % 4)) in + 0 ) j="-" ;; + 1 ) j="\\" ;; + 2 ) j="|" ;; + 3 ) j="/" ;; + esac + tput rc + echo -en "\r[$j] Waiting for other software managers to finish..." + sleep 0.5 + ((i=i+1)) + done +} + +apt_wait + +echo "Ubuntu update and install docker-compose..." ssh "$TLD" sudo apt-get update ssh "$TLD" sudo apt-get upgrade -y ssh "$TLD" sudo apt-get install -y docker-compose ssh "$TLD" sudo apt-get autoremove -y -green "Done.\n" +echo "Done.\n" -yellow "Copy over files..." +echo "Copy over files..." ssh "$TLD" mkdir -p /home/vps/ envsubst < docker-compose.yaml > docker-compose.yaml.fd scp docker-compose.yaml.fd "$TLD":/home/vps/docker-compose.yaml rm docker-compose.yaml.fd -green "Done.\n" +echo "Done.\n" -yellow "Restart docker-compose" -ssh "$TLD" "cd /home/vps/ && docker-compose down" +echo "Restart docker-compose" ssh "$TLD" "cd /home/vps/ && docker-compose pull" ssh "$TLD" "cd /home/vps/ && docker-compose up -d" -green "Done.\n" +echo "Done.\n" diff --git a/provision.sh b/provision.sh new file mode 100644 index 0000000..b13be57 --- /dev/null +++ b/provision.sh @@ -0,0 +1,36 @@ +#!/usr/bin/env bash +set -Eeuo pipefail +cd "${BASH_SOURCE%/*}/" + +echo "Unlocking git-crypt repositories and loading secrets..." +git crypt unlock +pushd ../vps-state/ +git crypt unlock +popd +source .envrc +echo "Done.\n" + +alias ssh="ssh -i secrets/id_rsa root@$TLD" + +echo "Shutting down running containers..." +ssh "cd /home/vps/ && docker-compose down" +echo "Done.\n" + +echo "Running `terraform apply`..." +terraform apply +echo "Done.\n" + +echo "Storing .tfstate file" +pushd ../vps-state/ +git add secrets/terraform.tfstate secrets/terraform.tfstate.backup +git commit -m "CI: update Terraform .tfstate files" +git push origin master +popd +echo "Done.\n" + +echo "Locking git-crypt repositories back..." +git crypt lock +pushd ../vps-state/ +git crypt lock +popd +echo "Done.\n" diff --git a/secrets/terraform.tfstate b/secrets/terraform.tfstate Binary files differdeleted file mode 100644 index 58d3d71..0000000 --- a/secrets/terraform.tfstate +++ /dev/null diff --git a/secrets/terraform.tfstate.backup b/secrets/terraform.tfstate.backup Binary files differdeleted file mode 100644 index f6e33dd..0000000 --- a/secrets/terraform.tfstate.backup +++ /dev/null diff --git a/terraform.tfstate b/terraform.tfstate index e3dc257..4fa5ae3 120000 --- a/terraform.tfstate +++ b/terraform.tfstate @@ -1 +1 @@ -secrets/terraform.tfstate
\ No newline at end of file +../vps-state/secrets/terraform.tfstate
\ No newline at end of file diff --git a/terraform.tfstate.backup b/terraform.tfstate.backup index 7916717..54845c8 120000 --- a/terraform.tfstate.backup +++ b/terraform.tfstate.backup @@ -1 +1 @@ -secrets/terraform.tfstate.backup
\ No newline at end of file +../vps-state/secrets/terraform.tfstate.backup
\ No newline at end of file @@ -25,4 +25,8 @@ resource "digitalocean_droplet" "vps" { private_key = "${file("${path.module}/secrets/id_rsa")}" timeout = "2m" } -} + + provisioner "remote-exec" { + script = "./deploy.sh" + } +}
\ No newline at end of file |