From 429bdef86cf49afd96f716381be521edd78ce882 Mon Sep 17 00:00:00 2001 From: Brandon Rozek Date: Fri, 8 May 2020 23:13:36 -0400 Subject: [PATCH] New Posts --- content/blog/autodeployterraform.md | 179 ++++++++++++++++++++ content/blog/sharedpackerterraformconfig.md | 85 ++++++++++ content/blog/snapshotswithpacker.md | 95 +++++++++++ 3 files changed, 359 insertions(+) create mode 100644 content/blog/autodeployterraform.md create mode 100644 content/blog/sharedpackerterraformconfig.md create mode 100644 content/blog/snapshotswithpacker.md diff --git a/content/blog/autodeployterraform.md b/content/blog/autodeployterraform.md new file mode 100644 index 0000000..8ff60c1 --- /dev/null +++ b/content/blog/autodeployterraform.md @@ -0,0 +1,179 @@ +--- +title: "Automatic Deployments with Terraform" +date: 2020-05-08T22:45:18-04:00 +draft: false +tags: [] +--- + +I have recently written about [Packer](https://brandonrozek.com/blog/snapshotswithpacker/) to create system images or snapshots. This post will go over another [HashiCorp](https://www.hashicorp.com/) project named [Terraform](https://www.terraform.io/) that we can use to deploy that image to a VPS. Like before, I am going to go over how to setup this up in DigitalOcean. Check out [this list](https://www.terraform.io/docs/providers/index.html) for documentation on your favorite cloud provider. + +## Variables + +To protect against committing secrets like API keys, we're going to create a file that only stores variables. For it to be loaded automatically, it needs to be named `terraform.tfvars`. Here is an example configuration: + +``` +region = "nyc3" +size = "512mb" +domain = "example.com" +subdomain = "temp" + +# Secrets +do_token = "DO-TOKEN-HERE" +key_name = "SSH-KEY-NAME-ON-DO" +``` + +Now to define the variables in HCL, we need to create a separate `variables.tf` file defining their types + +``` +variable "do_token" { + type = string +} + +variable "domain" { + type = string +} + +variable "key_name" { + type = string +} + +variable "subdomain" { + type = string +} + +variable "region" { + type = string +} + +variable "size" { + type = string +} + +``` + +## Configuration + +Now let's create a file called `do.tf`. We need to start off by stating which provider we are using + +``` +provider "digitalocean" { + token = var.do_token +} +``` + +If you want to hook up your SSH key, then we need to query the Digital Ocean API for its ID. + +``` +data "digitalocean_ssh_key" laptop { + name = var.key_name +} +``` + +We need to also query the API for the packer snapshot we created. Replace this with any standard image like `"ubuntu-20-04-x64"` if you don't want to use a snapshot. + +``` +data "digitalocean_droplet_snapshot" "packer_snapshot" { + name = "packer-example" + most_recent = true +} +``` + +Now we can create the droplet + +``` +resource "digitalocean_droplet" "web" { + name = "tf-1" + image = data.digitalocean_droplet_snapshot.packer_snapshot.id + region = var.region + size = var.size + ssh_keys = [data.digitalocean_ssh_key.laptop.id] + backups = false +} +``` + +Attach a domain to the droplet + +``` +resource "digitalocean_record" "www" { + domain = var.domain + type = "A" + name = var.subdomain + value = digitalocean_droplet.web.ipv4_address +} +``` + +Output useful pieces of information like the new system's IP address and the domain + +``` +output "ip" { + value = digitalocean_droplet.web.ipv4_address +} + +output "domain" { + value = "${digitalocean_record.www.name}.${digitalocean_record.www.domain}" +} +``` + +The whole configuration file for your convenience: + +``` +provider "digitalocean" { + token = var.do_token +} + +data "digitalocean_ssh_key" laptop { + name = var.key_name +} + +data "digitalocean_droplet_snapshot" "packer_snapshot" { + name = "packer-example" + most_recent = true +} + +# Create a droplet +resource "digitalocean_droplet" "web" { + name = "tf-1" + image = data.digitalocean_droplet_snapshot.packer_snapshot.id + region = var.region + size = var.size + ssh_keys = [data.digitalocean_ssh_key.laptop.id] + backups = false +} + +# Attach a subdomain +resource "digitalocean_record" "www" { + domain = var.domain + type = "A" + name = var.subdomain + value = digitalocean_droplet.web.ipv4_address +} + +output "ip" { + value = digitalocean_droplet.web.ipv4_address +} + +output "domain" { + value = "${digitalocean_record.www.name}.${digitalocean_record.www.domain}" +} +``` + +# Deploy + +Check if your configuration is valid + +```bash +terraform plan +``` + +Deploy! + +```bash +terraform apply +``` + +Take down when done + +```bash +terraform destroy +``` + diff --git a/content/blog/sharedpackerterraformconfig.md b/content/blog/sharedpackerterraformconfig.md new file mode 100644 index 0000000..d691a3e --- /dev/null +++ b/content/blog/sharedpackerterraformconfig.md @@ -0,0 +1,85 @@ +--- +title: "Shared Packer & Terraform Config" +date: 2020-05-08T22:59:30-04:00 +draft: false +tags: [] +--- + +You might have noticed from my last two posts on [Packer](https://brandonrozek.com/blog/snapshotswithpacker/) and [Terraform](https://brandonrozek.com/blog/autodeployterraform/) that the configuration files are highly similar. In fact, we can trick them into sharing a configuration file! + +## Shared Configuration + +First let's create a file we'll call `config` that contains all our assignments. Here is an example configuration: + +``` +base_system_image = "ubuntu-20-04-x64" +region = "nyc3" +size = "512mb" +domain = "example.com" +subdomain = "temp" + +# Secrets +do_token = "DO-TOKEN-HERE" +key_name = "KEY-NAME-ON-DO" +``` + +Then we'll create a file named `variables.hcl` that contains the type definitions + +``` +variable "do_token" { + type = string +} + +variable "base_system_image" { + type = string +} + +variable "domain" { + type = string +} + +variable "key_name" { + type = string +} + +variable "subdomain" { + type = string +} + +variable "region" { + type = string +} + +variable "size" { + type = string +} +``` + +## Packer + +Now to trick Packer into reading the configuration files we need to: + +- map `variables.auto.pkrvars.hcl` to `config` +- map `variables.pkr.hcl` to `variables.hcl` + +We can do this with symbolic links + +```bash +ln -s config variables.auto.pkrvars.hcl +ln -s variables.hcl variables.pkr.hcl +``` + +## Terraform + +To trick Terraform into reading the configuration files we need to: + +- map `terraform.tfvars ` to `config` +- map `variables.tf` to `variables.hcl` + +As before, we can do this with symbolic links + +```bash +ln -s config terraform.tfvars +ln -s variables.hcl variables.tf +``` + diff --git a/content/blog/snapshotswithpacker.md b/content/blog/snapshotswithpacker.md new file mode 100644 index 0000000..ae677f2 --- /dev/null +++ b/content/blog/snapshotswithpacker.md @@ -0,0 +1,95 @@ +--- +title: "Snapshot Creation with Packer" +date: 2020-05-08T22:31:40-04:00 +draft: false +tags: [] +--- + +[Packer](https://www.packer.io/) is a tool to create automated machine images in both local virtual machine / container environments, as well as a variety of cloud platforms. My current cloud platform of choice is [Digital Ocean](https://www.digitalocean.com/), so this post will explain how to set up Packer with it. Though you can likely find your platform of choice on their [docs](https://www.packer.io/docs/builders/) page + +In this post I am going to use the beta configuration language of HCL2. This requires a Packer version of at least 1.5. + +## Variables + +First let us set up a variables file which we will later reference. This makes it easy to keep your main Packer configuration files in Git, while not committing your API key. + +Create a file called `variables.auto.pkrvars.hcl`. Here is some example variables and values that I put in mine. + +``` +base_system_image = "ubuntu-20-04-x64" +region = "nyc3" +size = "512mb" +do_token = "DOTOKENHERE" # Secret +``` + +Then we need to create `variables.pkr.hcl` that define the types of each of these variables + +``` +variable "do_token" { + type = string +} + +variable "base_system_image" { + type = string +} + +variable "region" { + type = string +} + +variable "size" { + type = string +} +``` + +## Provisioning + +Once the system is up and running we can use a [variety of tools](https://www.packer.io/docs/provisioners/) that setup the image. + +- Ansible +- Chef +- Powershell +- etc. + +I'll use a simple bash script as an example + +```bash +#!/bin/bash +apt update +apt upgrade -y +``` + +## Piecing it together + +Finally let us create a `do.pkr.hcl` file that contains the following information + +``` +source "digitalocean" "web" { + api_token = var.do_token + image = var.base_system_image + region = var.region + size = var.size + ssh_username = "root" + snapshot_name = "packer-example" +} + + +build { + sources = [ + "source.digitalocean.web", + ] + + provisioner "shell" { + scripts = [ "setup.sh" ] + } +} +``` + +Assuming all the files we've just created are in the same directory, Packer will automatically recognize where the value for `var.do_token` lives. We can then run packer to build the image + +```bash +packer build . +``` + +This sets up a snapshot called `packer-example` which we can later spin up and use! Keep in mind that it does a small amount of money to store images on DigitalOcean. +