An instant Jekyll publishing environment in Azure
Made for… publishing blogs like this! Consists of a terraform script that creates a straightforward VM in Azure and an Ansible playbook that sets up the necessary software. It makes it easy to build a bit more of a fully featured system than a pre-packed container (e.g., editors, image manipulation software, etc).
The setup uses terraform and ansible, both which are pre-installed in Azure Cloud Shell and therefore deploying this is quick and convenient.
Note that in this version the disk is ephemeral and will be deleted when the environment is shutdown, so use git to store the actual content elsewhere.
To use
The scripts and some notes are given below, in this section are the commands to issue.
To create the VM:
terraform apply
Install the software:
ansible-playbook -i "`terraform output -raw vm_ip`," bnwebplay.yml
And finally ssh in:
ssh azureuser@`terraform output -raw vm_ip`
When done, destroy with (but note: disk will be deleted, so push changes to your git host):
terraform destroy
Terraform script
The architecture is the most straightforward virtual machine setup as illustrated below. Some notes:
-
The disk in this configuration will be deleted on shutdown, so this is useful for situation where all content is always pushed to a remote (git) repository after development
-
Port 22 is open to public to access via SSH
-
Use port forwarding to connect to Jekyll server
jekyll serve
-
Spot instance is used to reduce cost – there is some chance of eviction
-
There is a daily automatic shutdown to avoid accidentally long running vms
# Configure the Microsoft Azure Provider
terraform {
required_providers {
azurerm = {
source = "hashicorp/azurerm"
version = "~>2.0"
}
}
}
provider "azurerm" {
features {}
}
locals {
region= "uksouth"
}
# Create a resource group if it doesn't exist
resource "azurerm_resource_group" "webdev" {
name = "webdev"
location = local.region
}
# Create virtual network
resource "azurerm_virtual_network" "gen" {
name = "gennet"
address_space = ["10.0.0.0/16"]
location = local.region
resource_group_name = azurerm_resource_group.webdev.name
}
# Create subnet
resource "azurerm_subnet" "gensub" {
name = "gensub"
resource_group_name = azurerm_resource_group.webdev.name
virtual_network_name = azurerm_virtual_network.gen.name
address_prefixes = ["10.0.1.0/24"]
}
# Create public IPs
resource "azurerm_public_ip" "publicip" {
name = "jekyllpublicip"
location = local.region
resource_group_name = azurerm_resource_group.webdev.name
allocation_method = "Dynamic"
}
# Create Network Security Group and rule
resource "azurerm_network_security_group" "webdevsg" {
name = "webdevsg"
location = local.region
resource_group_name = azurerm_resource_group.webdev.name
security_rule {
name = "SSH"
priority = 1001
direction = "Inbound"
access = "Allow"
protocol = "Tcp"
source_port_range = "*"
destination_port_range = "22"
source_address_prefix = "*"
destination_address_prefix = "*"
}
}
# Create network interface
resource "azurerm_network_interface" "nic" {
name = "webdevnic"
location = local.region
resource_group_name = azurerm_resource_group.webdev.name
ip_configuration {
name = "nicfg"
subnet_id = azurerm_subnet.gensub.id
private_ip_address_allocation = "Dynamic"
public_ip_address_id = azurerm_public_ip.publicip.id
}
}
# Connect the security group to the network interface
resource "azurerm_network_interface_security_group_association" "example" {
network_interface_id = azurerm_network_interface.nic.id
network_security_group_id = azurerm_network_security_group.webdevsg.id
}
# Create virtual machine
resource "azurerm_linux_virtual_machine" "webdevvm" {
name = "webdev"
location = local.region
resource_group_name = azurerm_resource_group.webdev.name
network_interface_ids = [azurerm_network_interface.nic.id]
size = "Standard_DS1_v2"
priority = "Spot"
eviction_policy = "Deallocate"
os_disk {
name = "osdisk"
caching = "ReadWrite"
storage_account_type = "Premium_LRS"
}
source_image_reference {
publisher = "Canonical"
offer = "UbuntuServer"
sku = "18.04-LTS"
version = "latest"
}
computer_name = "webdev"
admin_username = "azureuser"
disable_password_authentication = true
admin_ssh_key {
username = "azureuser"
public_key = file("~/.ssh/id_rsa.pub")
}
}
output "vm_ip" {
value = azurerm_linux_virtual_machine.webdevvm.public_ip_address
}
resource "azurerm_dev_test_global_vm_shutdown_schedule" "sch" {
virtual_machine_id = azurerm_linux_virtual_machine.webdevvm.id
location = azurerm_resource_group.webdev.location
enabled = true
daily_recurrence_time = "2300"
timezone = "W. Europe Standard Time"
notification_settings {
enabled = false
}
}
Ansible playbook:
Save as bnwebplay.yml
:
---
- name: bnweb software stack
hosts: all
user: azureuser
tasks:
- name: install base packages
apt:
pkg: ['git', 'build-essential', 'ruby-full', 'ruby-dev', 'emacs-nox']
state: present
update_cache: yes
cache_valid_time: 604800
become: true
- name: install ruby dependencies
gem: name= state=present
with_items:
- bundler
- jekyll
- rake