Skip to content

Commit

Permalink
feat: add azure-instance
Browse files Browse the repository at this point in the history
  • Loading branch information
matihost committed Dec 4, 2024
1 parent ecf6178 commit 49ecc3d
Show file tree
Hide file tree
Showing 22 changed files with 544 additions and 3 deletions.
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ Various technology deployments, tools & code:
* aws-site - sample web site exposure via S3 and CloudFront
* aws-iam-management, aws-iam-linked - setup IAM resources needed on fresh AWS management account (users, roles, groups etc) and subsequent linked AWS accounts
* aws-network-setup - minimal AWS recommended setup with private subnet
* aws-instance - minimal VM setup
* aws-instance - VM setup
* aws-alb - Application Load Balancer usage
* aws-jenkins - Jenkins deployment as AWS VMs, Packer images for Jenkins Agents
* aws-lambda - sample AWS Lambda emulating a client hitting EC2 instance with AWS ApiGateway exposure
Expand All @@ -58,7 +58,9 @@ Various technology deployments, tools & code:
* ibm-alb - Application and Network Load Balancer usage
* ibm-ocp - IBM RedHat OpenShift Kubernetes Service (ROKS) deployment
* azure - Terragrunt / OpenTofu deployments for Azure
* ibm-entraid - setup IAM resource needed on fresh Azure subscription (resource group)
* azure-network-setup - minimal Azure recommended network setup
* azure-entraid - setup IAM resource needed on fresh Azure subscription (resource group)
* azure-instance - VM setup
* [scripts](scripts) - various bash scripts (tools for TLS handling, K8S etc.)
* [vagrant](vagrant) - CentOS VM buildout with Vagrant with various Linux networking tools examples
* [algorithms](algorithms/project-euler) - Java based project solving various <https://projecteuler.net> problems
Expand Down
2 changes: 1 addition & 1 deletion terraform/aws/aws-instance/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ Use AWS resources eliglible to AWS Free Tier __only__.

* Latest Terragrunt, Terraform or OpenTofu installed

* * [../aws-network-setup](../aws-network-setup) - installed for `dev` env, aka installation VM in own VPC. The `default` env deploys instance in the default VPC.
* [../aws-network-setup](../aws-network-setup) - installed for `dev` env, aka installation VM in own VPC. The `default` env deploys instance in the default VPC.

## Usage

Expand Down
54 changes: 54 additions & 0 deletions terraform/azure/azure-instance/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
.EXPORT_ALL_VARIABLES:

DEBUG := false
ifeq ($(strip $(DEBUG)),true)
TF_LOG := DEBUG
DEBUG_MODE :=--terragrunt-log-level debug --terragrunt-debug
endif

MODE := apply
ifeq ($(strip $(MODE)),apply)
MODE_STR := apply -auto-approve $(DEBUG_MODE)
else ifeq ($(strip $(MODE)),destroy)
MODE_STR := destroy -auto-approve $(DEBUG_MODE)
else
MODE_STR := plan $(DEBUG_MODE)
endif


ENV := dev-westeurope

init: init-tf-backend prepare
cd stage/$(ENV) && terragrunt init -upgrade=true


run: init ## setup VPC: make run [ENV=dev] [MODE=apply]
@cd stage/$(ENV) && terragrunt validate && terragrunt $(MODE_STR)

show-state: ## show state
cd stage/$(ENV) && terragrunt state list && terragrunt show

clean: ## clean cached plugins and data
find . -name ".terra*" -exec rm -rf {} +
find . -name "target" -exec rm -rf {} +

upgrade-providers-version: init


init-tf-backend:
cd stage && ./init_azurerm_tf_backend.sh

whoami: ## show current logon (tenant, subscription, user)
@az account show

login: ## login to Azure Subscription
az login

prepare:
@[ -e "$(HOME)/.ssh/id_rsa.cloud.vm" ] || { cd ~/.ssh && ssh-keygen -m PEM -t rsa -N '' -f id_rsa.cloud.vm; }


help: ## show usage and tasks (default)
@eval $$(sed -E -n 's/^([\*\.a-zA-Z0-9_-]+):.*?## (.*)$$/printf "\\033[36m%-30s\\033[0m %s\\n" "\1" "\2" ;/; ta; b; :a p' $(MAKEFILE_LIST))
.DEFAULT_GOAL := help
.PHONY: help run clean
31 changes: 31 additions & 0 deletions terraform/azure/azure-instance/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# Terraform :: VM Instnace

Setup single VM instance with Ngnix server on it.

## Prerequisites

* Latest Terraform installed
* [Azure CLI](https://learn.microsoft.com/en-us/cli/azure/install-azure-cli-linux?pivots=apt)

* Azure Subscription. Azure FreeTier Subscription is ok.

* Logged to Azure Subscription:

```bash
make login
```

* Initialize Azure Storage Account and Container for keeping Terraform state

```bash
make init
```

* [../azure-network-setup](../azure-network-setup) - installed for the same stage environment.

## Usage

```bash
# setup VM
make run MODE=apply ENV=dev-westeurope
```
100 changes: 100 additions & 0 deletions terraform/azure/azure-instance/module/variables.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
data "azurerm_subscription" "current" {
}

data "azurerm_resource_group" "rg" {
name = var.env
}

locals {
# tflint-ignore: terraform_unused_declarations
subscription_id = data.azurerm_subscription.current.id
resource_group_name = data.azurerm_resource_group.rg.name
location = var.region
prefix = "${var.env}-${var.region}"
}


variable "name" {
type = string
description = "VM name"
default = "vm"
}

variable "subnet_suffix" {
type = string
description = "Suffix of the name of the subnet"
default = "vms"
}

variable "size" {
type = string
description = "VM size"
default = "Standard_B2ats_v2" # 2 vcpu, 1 GiB memory
# Standard_B1ls (1 vcpu, 0.5 GiB memory)
# Standard_B1s (1 vcpu, 1 GiB memory)
}

variable "spot" {
type = bool
description = "Whether to use spot instead of regular instances"
default = true
}


variable "image" {
type = object({
admin_username = string
publisher = string
offer = string
sku = string
version = string
})
default = {
admin_username = "ubuntu"
publisher = "canonical"
offer = "ubuntu-24_04-lts"
sku = "minimal"
version = "latest"
}
description = "VM Image properties"
}


variable "ssh_pub_key" {
type = string
description = "The pem encoded SSH pub key for accessing VMs"
sensitive = true
}

variable "ssh_key" {
type = string
description = "The pem encoded SSH priv key to place on bastion"
sensitive = true
}


variable "user_data_template" {
type = string
description = "EC2 user_data conttent in tftpl format (aka with TF templating)"
}


# tflint-ignore: terraform_unused_declarations
variable "zone" {
default = "westeurope-az1"
type = string
description = "Preffered Azure AZ where resources need to placed, has to be compatible with region variable"
}

# tflint-ignore: terraform_unused_declarations
variable "region" {
default = "westeurope"
type = string
description = "Preffered Azure region where resource need to be placed"
}


variable "env" {
type = string
description = "Environment name, represents resource group"
}
12 changes: 12 additions & 0 deletions terraform/azure/azure-instance/module/versions.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
terraform {
required_providers {
azurerm = {
source = "hashicorp/azurerm"
version = "~> 4"
}
random = {
source = "hashicorp/random"
}
}
required_version = ">= 1.0"
}
75 changes: 75 additions & 0 deletions terraform/azure/azure-instance/module/vm.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
data "azurerm_virtual_network" "vnet" {
name = "${local.prefix}-vnet"
resource_group_name = local.resource_group_name
}

data "azurerm_subnet" "subnet" {
name = "${data.azurerm_virtual_network.vnet.name}-${var.subnet_suffix}"
virtual_network_name = data.azurerm_virtual_network.vnet.name
resource_group_name = local.resource_group_name
}

locals {
vm_name = "${local.prefix}-${var.name}"
}


resource "azurerm_ssh_public_key" "ssh" {
name = "${local.vm_name}-ssh"
location = local.location
resource_group_name = local.resource_group_name
public_key = var.ssh_pub_key
}

resource "azurerm_network_interface" "nic" {
name = "${local.vm_name}-nic"
location = local.location
resource_group_name = local.resource_group_name

ip_configuration {
name = "internal"
subnet_id = data.azurerm_subnet.subnet.id
private_ip_address_allocation = "Dynamic"
}
}

resource "azurerm_linux_virtual_machine" "linux" {
name = local.vm_name
location = local.location
# Do not provide zone to let Azure choose zone where instance type is present...
# zone = var.zone
resource_group_name = local.resource_group_name
size = var.size
admin_username = var.image.admin_username
network_interface_ids = [
azurerm_network_interface.nic.id,
]

priority = var.spot ? "Spot" : "Regular"
eviction_policy = var.spot ? "Delete" : null

# TODO test user_data instead
# https://learn.microsoft.com/en-us/azure/virtual-machines/user-data
custom_data = base64encode(templatestring(var.user_data_template, {
ssh_key = base64encode(var.ssh_key),
ssh_pub = base64encode(var.ssh_pub_key),
admin_username = var.image.admin_username
}))

admin_ssh_key {
username = var.image.admin_username
public_key = azurerm_ssh_public_key.ssh.public_key
}

os_disk {
caching = "ReadWrite"
storage_account_type = "Standard_LRS"
}

source_image_reference {
publisher = var.image.publisher
offer = var.image.offer
sku = var.image.sku
version = var.image.version
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
include {
path = find_in_parent_folders()
}

locals {
env = "dev"
region = "polandcentral"
zone = "polandcentral-az1"
pub_ssh = try(file("~/.ssh/id_rsa.cloud.vm.pub"), get_env("SSH_PUB", ""))
ssh_key = try(file("~/.ssh/id_rsa.cloud.vm"), get_env("SSH_PRIV", ""))
user_data_template = file("vm.cloud-init.tpl")
}

terraform {
# https://github.com/gruntwork-io/terragrunt/issues/1675
source = "${find_in_parent_folders("module")}///"
}


inputs = {
name = "vm"
env = "dev"
region = local.region
zone = local.zone
ssh_pub_key = local.pub_ssh
ssh_key = local.ssh_key
user_data_template = local.user_data_template
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#cloud-config
# Azure place VM configuration in /var/lib/waagent/ovf-env.xml
# VM location of cloud-init configuration: /var/lib/cloud/instance/cloud-config.txt
# Cloud-init output logs: /var/log/cloud-init-output.log
---
repo_update: true
repo_upgrade: all

packages:
- nginx
- plocate
- azure-cli

# cloud-init creates a final script in: /var/lib/cloud/instance/scripts/runcmd
runcmd:
- systemctl enable --now nginx
- echo -n "${ssh_pub}" |base64 -d > /home/${admin_username}/.ssh/id_rsa.pub
- echo -n "${ssh_key}" |base64 -d > /home/${admin_username}/.ssh/id_rsa
- cat /home/${admin_username}/.ssh/id_rsa.pub >> /home/${admin_username}/.ssh/authorized_keys
- 'chown ${admin_username}:${admin_username} /home/${admin_username}/.ssh/id_rsa*'
- chmod 400 /home/${admin_username}/.ssh/id_rsa
28 changes: 28 additions & 0 deletions terraform/azure/azure-instance/stage/dev-westeurope/terragrunt.hcl
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
include {
path = find_in_parent_folders()
}

locals {
env = "dev"
region = "westeurope"
zone = "westeurope-az1"
pub_ssh = try(file("~/.ssh/id_rsa.cloud.vm.pub"), get_env("SSH_PUB", ""))
ssh_key = try(file("~/.ssh/id_rsa.cloud.vm"), get_env("SSH_PRIV", ""))
user_data_template = file("vm.cloud-init.tpl")
}

terraform {
# https://github.com/gruntwork-io/terragrunt/issues/1675
source = "${find_in_parent_folders("module")}///"
}


inputs = {
name = "vm"
env = "dev"
region = local.region
zone = local.zone
ssh_pub_key = local.pub_ssh
ssh_key = local.ssh_key
user_data_template = local.user_data_template
}
Loading

0 comments on commit 49ecc3d

Please sign in to comment.