Skip to content

Commit

Permalink
feat: O11y cluster - Packer, Terraform and Ansible
Browse files Browse the repository at this point in the history
  • Loading branch information
raisedadead committed Jun 15, 2023
1 parent fab115d commit db4d197
Show file tree
Hide file tree
Showing 34 changed files with 668 additions and 197 deletions.
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
name: TF -- Linode - Cluster o11y
name: TF -- Linode - Ops Cluster o11y

on:
pull_request:
branches:
- main
paths:
- 'terraform/cluster-o11y/**'
- 'terraform/ops-cluster-o11y/**'

env:
TF_CLOUD_ORGANIZATION: freecodecamp
TF_API_TOKEN: ${{ secrets.TF_API_TOKEN }}
TF_WORKSPACE: tfws-ops-o11y
CONFIG_DIRECTORY: terraform/cluster-o11y
CONFIG_DIRECTORY: terraform/ops-cluster-o11y
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

jobs:
Expand Down
54 changes: 9 additions & 45 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,29 +1,3 @@
**/*.txt
*.pem
manifest.json

*.env
scratchpad/
*.act.secrets

# keys
*id_rsa*

# other
.idea
.DS_Store
*.out
secrets.auto.tfvars
.envrc
*.zip
*.gz
*.tgz
*.env*
.vscode

**/coverage/*

### Terraform ###
# Local .terraform directories
**/.terraform/*

Expand All @@ -33,13 +7,14 @@ secrets.auto.tfvars

# Crash log files
crash.log
crash.*.log

# Exclude all .tfvars files, which are likely to contain sentitive data, such as
# Exclude all .tfvars files, which are likely to contain sensitive data, such as
# password, private keys, and other secrets. These should not be part of version
# control as they are data points which are potentially sensitive and subject
# to change depending on the environment.
#
*.tfvars
*.tfvars.json

# Ignore override files as they are usually used to override resources locally and so
# are not checked in
Expand All @@ -58,22 +33,11 @@ override.tf.json
.terraformrc
terraform.rc

tsconfig.tsbuildinfo
*.d.ts
*.js

node_modules
cdktf.out
cdktf.log

*terraform.*.tfstate*
.gen
.terraform
# Ignore Visual Studio Code files
.vscode/

tf-cdk-ts/scripts/data/
# Ignore User-specific temporary files
__scratchpad__/

!jest.config.js
!setup.js
!.eslintrc.js

dist
# Ignore generated files
manifest.json
22 changes: 22 additions & 0 deletions ansible/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
SHELL := /bin/bash

.DEFAULT_GOAL := help

.PHONY: help
help:
@echo "Usage: make [Target] [Environment Variables]"
@echo ""
@echo "Targets:"
@echo " help Show this help message"
@echo " install Install ansible and ansible-lint"


.PHONY: install
install:
pip install ansible ansible-lint
pip install -r requirements.txt
ansible-galaxy install -r requirements.yml

.PHONY: check-inventory
check-inventory:
ansible-inventory -i inventory --graph
12 changes: 12 additions & 0 deletions ansible/ansible.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
[defaults]
python_interpreter=/usr/bin/python3
host_key_checking=false
stdout_callback=yaml
ansible_user=freecodecamp
remote_user=freecodecamp

[inventory]
enable_plugins = community.general.linode
cache = true
cache_connection = ~/.ansible/.cache
cache_timeout = 60
12 changes: 12 additions & 0 deletions ansible/inventory/o11y/linode.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# IMPORTANT: This file has to be be named linode.yml or linode.yaml
# See: https://github.com/ansible-collections/community.general/blob/011b2f8bdc2a042f0eb44739ff51ce425f391afa/plugins/inventory/linode.py#L274

plugin: community.general.linode # can be replaced with linode.cloud.instance, when they support Jinja2 template strings
access_token: "{{ lookup('env', 'LINODE_API_TOKEN') }}"

groups:
managers: "'o11y_leader' in (tags|list)"
workers: "'o11y_worker' in (tags|list)"

compose:
ansible_ssh_host: ipv4[0]
8 changes: 8 additions & 0 deletions ansible/play-o11y--0-initialize.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
- name: Initialize a O11y Cluster
hosts: all
become: true
roles:
- ubuntu # Update the OS and reboot the server
- dns # Configure ansible facts for networking info lookup
- docker # Intialize docker and docker swarm cluster
11 changes: 11 additions & 0 deletions ansible/play-o11y--9-uptime.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
- name: Check uptime on virtual machines
hosts: '{{ variable_host | default("all") }}'
gather_facts: true
become_user: root
tasks:
- name: Print uptime
debug:
msg:
'Host machine {{ inventory_hostname }} has been up for {{
ansible_facts.uptime_seconds/86400 }} days'
51 changes: 51 additions & 0 deletions ansible/play-test--0-docker-swarm.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
---
- name: Start a docker swarm cluster and test it
hosts: all
become: true
vars:
# Use `--extra-vars '{ "variable_purge_test" : false }'` to skip
# deleteing the resources. This is helpful if you want to keep
# debugging manually after the playbook run is finished.
purge_test: '{{ variable_purge_test | default(true) }}'

roles:
- ubuntu # Update the OS and reboot the server
- dns # Configure ansible facts for networking info lookup
- docker # Intialize docker and docker swarm cluster

tasks:
- name: Run a docker container
docker_container:
name: echo
image: hashicorp/http-echo
state: started
restart_policy: always
command: ['-text', 'hello world from {{ ansible_hostname }}']
ports:
- '5080:5678'

- name: Test the docker container
uri:
url: http://localhost:5080
return_content: yes
register: result

- name: Print the result
debug:
msg: '{{ result.content }}'

- name: Stop the docker container
docker_container:
name: echo
image: hashicorp/http-echo
state: absent
when: purge_test

- name: Prune the docker system
docker_prune:
images: yes
containers: yes
volumes: yes
networks: yes
builder_cache: yes
when: purge_test
4 changes: 4 additions & 0 deletions ansible/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
linode-api4>=5.5.1
polling>=0.3.2
types-requests==2.31.0.1
ansible-specdoc>=0.0.13
4 changes: 4 additions & 0 deletions ansible/requirements.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
---
collections:
- community.general
- community.docker
18 changes: 18 additions & 0 deletions ansible/roles/dns/tasks/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
---
# We expect the /etc/hostname file to be populated with a FQDN
# when the host is provisioned, using terraform or cloud-init.
#
# The FQDN should point to a Public IP address that is resolvable
#
- name: Get Hostname from /etc/hostname
slurp:
src: /etc/hostname
register: hostname

- name: Set the anisble_fqdn
set_fact:
ansible_fqdn: "{{ hostname['content'] | b64decode }}"

- name: Print the ansible_fqdn
debug:
var: ansible_fqdn
15 changes: 15 additions & 0 deletions ansible/roles/docker/defaults/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
---
# defaults file for roles/docker

docker_packages:
- apt-transport-https
- ca-certificates
- curl
- software-properties-common
- docker-ce
- docker-ce-cli
- containerd.io
- python3-docker
docker_repo: deb [arch=amd64] https://download.docker.com/linux/{{ ansible_distribution|lower }} {{ ansible_distribution_release }} stable
docker_repo_key: https://download.docker.com/linux/ubuntu/gpg
docker_repo_key_id: 0EBFCD88
29 changes: 29 additions & 0 deletions ansible/roles/docker/tasks/install-docker.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# tasks file for roles/docker
---
- name: add gpg key
apt_key:
url: "{{ docker_repo_key }} "
state: present

- name: Add repository
apt_repository:
repo: "{{ docker_repo }}"

- name: install docker and dependencies
apt:
name: "{{ docker_packages }}"
state: latest
update_cache: yes
cache_valid_time: 3600
with_items: "{{ docker_packages}}"

- name: Add user to docker group
user:
name: "{{ ansible_user }}"
group: docker

- name: start docker
service:
name: docker
state: started
enabled: yes
55 changes: 55 additions & 0 deletions ansible/roles/docker/tasks/install-swarm.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# tasks file for roles/swarm
---
- name: Retrieve the initial Swarm Info
community.docker.docker_swarm_info:
register: swarm_info_initial
when: inventory_hostname == groups['managers'][0]
ignore_errors: true
no_log: "{{ variable_no_log | default (true) }}"
changed_when: swarm_info_initial.docker_swarm_active == false

- name: Initialize Swarm
community.docker.docker_swarm:
state: present
advertise_addr: "{{ ansible_default_ipv4.address }}"
listen_addr: "{{ ansible_default_ipv4.address }}:2377"
when: inventory_hostname == groups['managers'][0] and swarm_info_initial.docker_swarm_active == false
no_log: "{{ variable_no_log | default (true) }}"

- name: Refresh the Swarm Info
community.docker.docker_swarm_info:
nodes: true
register: swarm_info
when: inventory_hostname == groups['managers'][0]
no_log: "{{ variable_no_log | default (true) }}"

# TODO: Add checks and add more managers if needed

- name: Set useful information on Workers as Facts
set_fact:
swarm_join_token_worker: "{{ hostvars[groups['managers'][0]]['swarm_info']['swarm_facts']['JoinTokens']['Worker'] }}"
swarm_manager_addr: "{{ hostvars[groups['managers'][0]]['ansible_default_ipv4']['address'] }}"
when: inventory_hostname in groups['workers']
no_log: "{{ variable_no_log | default (true) }}"

- name: Join Swarm as worker using token
community.docker.docker_swarm:
state: join
advertise_addr: "{{ ansible_default_ipv4.address }}"
join_token: "{{ swarm_join_token_worker }}"
remote_addrs: [
"{{ swarm_manager_addr }}"
]
when: inventory_hostname in groups['workers']

- name: List Swarm Nodes
community.docker.docker_swarm_info:
nodes: true
when: inventory_hostname == groups['managers'][0]
register: result
no_log: "{{ variable_no_log | default (true) }}"

- name: Print Swarm Nodes
debug:
msg: "{{ result.nodes }}"
when: inventory_hostname == groups['managers'][0]
16 changes: 16 additions & 0 deletions ansible/roles/docker/tasks/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
---
- name: Check if Docker is installed
stat:
path: /usr/bin/docker
register: docker_installed

- name: Install Docker if not installed using the role
include_role:
name: docker
tasks_from: install-docker.yml
when: docker_installed.stat.exists == false

- name: Initialize Swarm using the role
include_role:
name: docker
tasks_from: install-swarm.yml
6 changes: 6 additions & 0 deletions ansible/roles/ubuntu/tasks/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
- name: Update
import_tasks: update.yml

- name: Reboot
import_tasks: reboot.yml
8 changes: 8 additions & 0 deletions ansible/roles/ubuntu/tasks/reboot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
- name: Reboot
ansible.builtin.reboot:
connect_timeout: 5
reboot_timeout: 300
pre_reboot_delay: 120
post_reboot_delay: 120
test_command: uptime
Loading

0 comments on commit db4d197

Please sign in to comment.