mirror of
https://github.com/Brandon-Rozek/website.git
synced 2024-11-29 10:17:06 -05:00
New Posts
This commit is contained in:
parent
ea27801577
commit
429bdef86c
3 changed files with 359 additions and 0 deletions
179
content/blog/autodeployterraform.md
Normal file
179
content/blog/autodeployterraform.md
Normal file
|
@ -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
|
||||||
|
```
|
||||||
|
|
85
content/blog/sharedpackerterraformconfig.md
Normal file
85
content/blog/sharedpackerterraformconfig.md
Normal file
|
@ -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
|
||||||
|
```
|
||||||
|
|
95
content/blog/snapshotswithpacker.md
Normal file
95
content/blog/snapshotswithpacker.md
Normal file
|
@ -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.
|
||||||
|
|
Loading…
Reference in a new issue