feat: Enhance website deployment and build process
- Added rsync installation in setup-env action for file synchronization. - Excluded playbook_websites.yml from ansible-apply-playbook workflow. - Created a new workflow for building and releasing the Hugo website. - Added submodule for Hugo theme in .gitmodules. - Updated host_vars for production to include websites configuration. - Introduced playbook_websites.yml for managing static files deployment. - Implemented hugo_build script for building and archiving Hugo sites. - Updated inventory to include a new web group for website deployment. - Refactored Terraform configuration to support new website structure. - Removed deprecated WordPress Terraform configuration. - Added .gitignore files for websites and specific Hugo site. - Created archetype and configuration files for the Hugo site. - Added static assets including CV and images for the Hugo site. - Integrated Hugo profile theme as a submodule for the website.
This commit is contained in:
@@ -22,4 +22,4 @@ runs:
|
||||
shell: bash
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y python3-pip
|
||||
sudo apt-get install -y python3-pip rsync
|
||||
|
||||
@@ -5,6 +5,7 @@ on:
|
||||
- main
|
||||
paths:
|
||||
- ansible/playbook_*.yml
|
||||
- '!ansible/playbook_websites.yml'
|
||||
jobs:
|
||||
ansible-apply:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
name: Build and Release Hugo Website
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
paths:
|
||||
- 'ansible/playbook_websites.yml'
|
||||
- 'websites/**'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Build Hugo Website
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout Code
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: true
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Setup Hugo
|
||||
uses: peaceiris/actions-hugo@v2
|
||||
with:
|
||||
hugo-version: 'latest'
|
||||
|
||||
- name: Setup environment
|
||||
id: setup_env
|
||||
uses: ./.github/actions/setup-env
|
||||
|
||||
- name: Setup Ansible environment
|
||||
uses: ./.github/actions/setup-ansible-env
|
||||
with:
|
||||
project-id: ${{ secrets.BW_PROJECT_ID }}
|
||||
organization-id: ${{ secrets.BW_ORGANIZATION_ID }}
|
||||
access-token: ${{ secrets.BW_ACCESS_TOKEN }}
|
||||
ansible-user: ${{ secrets.ANSIBLE_USER }}
|
||||
trusted-hosts: ${{ secrets.TRUSTED_HOSTS }}
|
||||
|
||||
- name: Run hugo_build command
|
||||
run: bin/hugo_build.sh
|
||||
|
||||
- name: Run the playbook to deploy websites
|
||||
env:
|
||||
BW_PROJECT_ID: ${{ secrets.BW_PROJECT_ID }}
|
||||
BW_ORGANIZATION_ID: ${{ secrets.BW_ORGANIZATION_ID }}
|
||||
BW_ACCESS_TOKEN: ${{ secrets.BW_ACCESS_TOKEN }}
|
||||
ANSIBLE_USER: ${{ secrets.ANSIBLE_USER }}
|
||||
SSH_AUTH_SOCK: /tmp/ssh_agent.sock
|
||||
CHANGED_FILES: ${{ steps.setup_env.outputs.CHANGED_FILES }}
|
||||
run: |
|
||||
cd ansible
|
||||
sectool -f ../sectool.json exec ansible-playbook -u $ANSIBLE_USER playbook_websites.yml
|
||||
@@ -0,0 +1,3 @@
|
||||
[submodule "websites/themes/hugo-profile"]
|
||||
path = websites/themes/hugo-profile
|
||||
url = https://github.com/gurusabarish/hugo-profile.git
|
||||
@@ -163,3 +163,7 @@ duo_api_hostname: api-7cda1654.duosecurity.com
|
||||
# Apps
|
||||
persistent_data: "/mnt/microk8s_persistent"
|
||||
database_path: "/var/lib"
|
||||
|
||||
# Websites
|
||||
websites:
|
||||
- "alexpires.me"
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
---
|
||||
- name: Websites (Static Files) Playbook (K8s)
|
||||
hosts: web
|
||||
gather_facts: true
|
||||
|
||||
# Specific tasks for this playbook
|
||||
tasks:
|
||||
- name: Set required facts
|
||||
ansible.builtin.set_fact:
|
||||
web_home: "{{ persistent_data | default('/var/lib') }}/web"
|
||||
web_user_id: 1000
|
||||
web_group_id: 1000
|
||||
tags: always
|
||||
|
||||
- name: Create required web data folder
|
||||
become: true
|
||||
ansible.builtin.file:
|
||||
state: directory
|
||||
path: "{{ web_home }}"
|
||||
mode: "0750"
|
||||
owner: "{{ web_user_id }}"
|
||||
group: "{{ web_group_id }}"
|
||||
tags:
|
||||
- tasks
|
||||
- tasks::folders
|
||||
|
||||
- name: Create required web data folder
|
||||
become: true
|
||||
ansible.builtin.file:
|
||||
state: directory
|
||||
path: "{{ web_home }}/{{ item }}"
|
||||
mode: "0750"
|
||||
owner: "{{ web_user_id }}"
|
||||
group: "{{ web_group_id }}"
|
||||
with_items:
|
||||
- "{{ websites | default([]) }}"
|
||||
tags:
|
||||
- tasks
|
||||
- tasks::folders
|
||||
|
||||
- name: Synchronize websites
|
||||
become: true
|
||||
ansible.posix.synchronize:
|
||||
mode: push
|
||||
src: "{{ lookup('env', 'GITHUB_WORKSPACE') + '/websites/releases/'+ item }}/"
|
||||
dest: "{{ web_home }}/{{ item }}"
|
||||
delete: yes
|
||||
recursive: yes
|
||||
with_items:
|
||||
- "{{ websites | default([]) }}"
|
||||
Executable
+34
@@ -0,0 +1,34 @@
|
||||
#!/bin/bash
|
||||
# This script is used to build a Hugo site and prepare it for deployment.
|
||||
GITHUB_WORKSPACE=${GITHUB_WORKSPACE:-$(pwd)}
|
||||
|
||||
command -v hugo >/dev/null 2>&1 || { echo >&2 "Hugo is not installed. Please install Hugo to use this script."; exit 1; }
|
||||
|
||||
mkdir -p "$GITHUB_WORKSPACE/websites/releases"
|
||||
|
||||
for dir in $(find "$GITHUB_WORKSPACE/websites" -maxdepth 1 -type d | grep -vE '^\.$'); do
|
||||
if [ "$dir" == "$GITHUB_WORKSPACE/websites" ]; then
|
||||
echo "Skipping $dir"
|
||||
continue
|
||||
fi
|
||||
if [ "$dir" == "$GITHUB_WORKSPACE/websites/themes" ]; then
|
||||
echo "Skipping $dir"
|
||||
continue
|
||||
fi
|
||||
if [ "$dir" == "$GITHUB_WORKSPACE/websites/releases" ]; then
|
||||
echo "Skipping $dir"
|
||||
continue
|
||||
fi
|
||||
if [ -d "$dir" ]; then
|
||||
echo "Building Hugo site in $dir"
|
||||
cd "$dir" || exit 1
|
||||
hugo --minify --themesDir $GITHUB_WORKSPACE/websites/themes --destination $GITHUB_WORKSPACE/websites/releases/$(basename "$dir") --baseURL "https://$(basename "$dir").example.com"
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Hugo build failed in $dir"
|
||||
exit 1
|
||||
fi
|
||||
echo "Hugo site built successfully in $dir"
|
||||
else
|
||||
echo "$dir is not a directory"
|
||||
fi
|
||||
done
|
||||
+3
-3
@@ -10,9 +10,6 @@ prod-01.alexpires.me
|
||||
[gitea]
|
||||
prod-01.alexpires.me
|
||||
|
||||
[wordpress]
|
||||
prod-01.alexpires.me
|
||||
|
||||
[nextcloud]
|
||||
prod-01.alexpires.me
|
||||
|
||||
@@ -33,3 +30,6 @@ prod-01.alexpires.me
|
||||
|
||||
[mail]
|
||||
prod-01.alexpires.me
|
||||
|
||||
[web]
|
||||
prod-01.alexpires.me
|
||||
|
||||
+12
-11
@@ -1,25 +1,26 @@
|
||||
locals {
|
||||
|
||||
# general
|
||||
domain_name = "alexpires.me"
|
||||
|
||||
# storage
|
||||
persistent_folder = "/mnt/microk8s_persistent"
|
||||
database_folder = "/var/lib"
|
||||
|
||||
# apps
|
||||
wordpress_version = "6.7.2"
|
||||
wordpress_fqdns = ["blog.${local.domain_name}", "www.${local.domain_name}", "${local.domain_name}"]
|
||||
wordpress_sql_backup_cron_schedule = "0 2 * * *"
|
||||
wordpress_files_backup_cron_schedule = "10 2 * * *"
|
||||
# domains
|
||||
primary_domain = "alexpires.me"
|
||||
websites = {
|
||||
"alexpires.me" = {
|
||||
domain_name = "alexpires.me"
|
||||
fqdn = ["blog.alexpires.me", "www.alexpires.me", "alexpires.me"]
|
||||
}
|
||||
}
|
||||
|
||||
gitea_version = "1.23.4"
|
||||
gitea_fqdn = "code.${local.domain_name}"
|
||||
gitea_fqdn = "code.${local.primary_domain}"
|
||||
gitea_sql_backup_cron_schedule = "20 2 * * *"
|
||||
gitea_files_backup_cron_schedule = "30 2 * * *"
|
||||
|
||||
nextcloud_version = "30.0.0-apache"
|
||||
nextcloud_fqdn = "cloud.${local.domain_name}"
|
||||
nextcloud_fqdn = "cloud.${local.primary_domain}"
|
||||
nextcloud_sql_backup_cron_schedule = "40 2 * * *"
|
||||
nextcloud_files_backup_cron_schedule = "50 2 * * *"
|
||||
|
||||
@@ -34,7 +35,7 @@ locals {
|
||||
m3uproxy_version = "latest"
|
||||
wireguard_version = "1.0.20210914-r4-ls54"
|
||||
squid_version = "6.1-23.10_edge"
|
||||
m3uproxy_fqdn = "tv.${local.domain_name}"
|
||||
m3uproxy_fqdn = "tv.${local.primary_domain}"
|
||||
geoip_image = "maxmindinc/geoipupdate"
|
||||
geoip_version = "latest"
|
||||
|
||||
@@ -47,7 +48,7 @@ locals {
|
||||
|
||||
# rustdesk
|
||||
rustdesk_version = "latest"
|
||||
rustdesk_fqdn = "rustdesk.${local.domain_name}"
|
||||
rustdesk_fqdn = "rustdesk.${local.primary_domain}"
|
||||
|
||||
# backup
|
||||
local_backup_retention_days = 2
|
||||
|
||||
@@ -25,10 +25,10 @@ locals {
|
||||
# Email configuration
|
||||
SMTP_HOST = local.scaleway_smtp_host
|
||||
SMTP_PORT = 465
|
||||
MY_PRIMARY_DOMAIN = local.domain_name
|
||||
MY_PRIMARY_DOMAIN = local.primary_domain
|
||||
MY_DESTINATION = join(",", [for account in local.email_accounts : account.domain])
|
||||
MY_NETWORKS = "127.0.0.0/8"
|
||||
MAILNAME = "smtp.${local.domain_name}"
|
||||
MAILNAME = "smtp.${local.primary_domain}"
|
||||
DOVECOT_AUTH_ADDRESS = "dovecot-auth.mail.svc.cluster.local"
|
||||
DOVECOT_AUTH_PORT = 31000
|
||||
DOVECOT_LMTP_ADDRESS = "dovecot-lmtp.mail.svc.cluster.local"
|
||||
@@ -201,8 +201,8 @@ resource "kubernetes_manifest" "mail_certificate" {
|
||||
name = "letsencrypt-prod"
|
||||
kind = "ClusterIssuer"
|
||||
}
|
||||
commonName = "imap.${local.domain_name}"
|
||||
dnsNames = ["imap.${local.domain_name}", "smtp.${local.domain_name}"]
|
||||
commonName = "imap.${local.primary_domain}"
|
||||
dnsNames = flatten([for account in local.email_accounts : ["imap.${account.domain}", "smtp.${account.domain}"]])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
server {
|
||||
listen 8080;
|
||||
server_name localhost;
|
||||
|
||||
gzip on;
|
||||
gzip_comp_level 9;
|
||||
gzip_types
|
||||
text/html
|
||||
text/plain
|
||||
text/css
|
||||
text/js
|
||||
text/xml
|
||||
text/javascript
|
||||
application/javascript
|
||||
application/json
|
||||
application/xml
|
||||
application/rss+xml
|
||||
image/svg+xml;
|
||||
|
||||
root /tmp/site;
|
||||
|
||||
location / {
|
||||
index index.html index.htm;
|
||||
}
|
||||
|
||||
location ~* ^/([^/]+) {
|
||||
index index.html index.htm;
|
||||
error_page 404 = @error;
|
||||
}
|
||||
|
||||
error_page 404 /404.html;
|
||||
location @error {
|
||||
try_files /$1/404.html /404.html =404;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
worker_processes auto;
|
||||
|
||||
error_log /var/log/nginx/error.log notice;
|
||||
pid /tmp/nginx.pid;
|
||||
|
||||
|
||||
events {
|
||||
worker_connections 1024;
|
||||
}
|
||||
|
||||
|
||||
http {
|
||||
proxy_temp_path /tmp/proxy_temp;
|
||||
client_body_temp_path /tmp/client_temp;
|
||||
fastcgi_temp_path /tmp/fastcgi_temp;
|
||||
uwsgi_temp_path /tmp/uwsgi_temp;
|
||||
scgi_temp_path /tmp/scgi_temp;
|
||||
|
||||
include /etc/nginx/mime.types;
|
||||
default_type application/octet-stream;
|
||||
|
||||
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
|
||||
'$status $body_bytes_sent "$http_referer" '
|
||||
'"$http_user_agent" "$http_x_forwarded_for"';
|
||||
|
||||
access_log /var/log/nginx/access.log main;
|
||||
|
||||
sendfile on;
|
||||
|
||||
keepalive_timeout 65;
|
||||
|
||||
|
||||
include /etc/nginx/conf.d/*.conf;
|
||||
}
|
||||
@@ -0,0 +1,201 @@
|
||||
locals {
|
||||
websites_path = "${local.persistent_folder}/web"
|
||||
}
|
||||
|
||||
resource "kubernetes_namespace" "website" {
|
||||
metadata {
|
||||
annotations = {
|
||||
name = "website"
|
||||
}
|
||||
|
||||
labels = {
|
||||
name = "website"
|
||||
}
|
||||
|
||||
name = "website"
|
||||
}
|
||||
}
|
||||
|
||||
resource "kubernetes_service_account" "website_service_account" {
|
||||
|
||||
metadata {
|
||||
name = "website-app-sa"
|
||||
namespace = kubernetes_namespace.website.metadata[0].name
|
||||
}
|
||||
|
||||
automount_service_account_token = false
|
||||
}
|
||||
|
||||
|
||||
resource "kubernetes_service" "website" {
|
||||
for_each = local.websites
|
||||
metadata {
|
||||
name = format("website-%s", replace(each.key, ".", "-"))
|
||||
namespace = kubernetes_namespace.website.metadata[0].name
|
||||
}
|
||||
spec {
|
||||
port {
|
||||
port = 80
|
||||
target_port = "http"
|
||||
}
|
||||
selector = {
|
||||
app = format("website-%s", replace(each.key, ".", "-"))
|
||||
}
|
||||
cluster_ip = "None"
|
||||
}
|
||||
}
|
||||
|
||||
resource "kubernetes_config_map" "nginx_config" {
|
||||
metadata {
|
||||
name = "nginx-config"
|
||||
namespace = kubernetes_namespace.website.metadata[0].name
|
||||
}
|
||||
|
||||
data = {
|
||||
"nginx.conf" = file("${path.module}/resources/nginx/nginx.conf")
|
||||
"default.conf" = file("${path.module}/resources/nginx/conf.d/default.conf")
|
||||
}
|
||||
}
|
||||
|
||||
resource "kubernetes_ingress_v1" "website_ingress" {
|
||||
for_each = local.websites
|
||||
metadata {
|
||||
name = "website-ingress"
|
||||
namespace = kubernetes_namespace.website.metadata[0].name
|
||||
|
||||
annotations = {
|
||||
"kubernetes.io/ingress.class" = "public"
|
||||
"cert-manager.io/cluster-issuer" = "letsencrypt-prod"
|
||||
}
|
||||
}
|
||||
spec {
|
||||
tls {
|
||||
hosts = each.value.fqdn
|
||||
secret_name = format("website-%s-tls", replace(each.key, ".", "-"))
|
||||
}
|
||||
dynamic "rule" {
|
||||
for_each = each.value.fqdn
|
||||
content {
|
||||
host = rule.value
|
||||
http {
|
||||
path {
|
||||
backend {
|
||||
service {
|
||||
name = format("website-%s", replace(each.key, ".", "-"))
|
||||
port {
|
||||
number = 80
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resource "kubernetes_deployment" "website" {
|
||||
for_each = local.websites
|
||||
|
||||
metadata {
|
||||
name = "website-app"
|
||||
namespace = kubernetes_namespace.website.metadata[0].name
|
||||
}
|
||||
spec {
|
||||
selector {
|
||||
match_labels = {
|
||||
app = format("website-%s", replace(each.key, ".", "-"))
|
||||
}
|
||||
}
|
||||
strategy {
|
||||
type = "RollingUpdate"
|
||||
}
|
||||
template {
|
||||
metadata {
|
||||
labels = {
|
||||
app = format("website-%s", replace(each.key, ".", "-"))
|
||||
}
|
||||
}
|
||||
spec {
|
||||
service_account_name = kubernetes_service_account.website_service_account.metadata[0].name
|
||||
|
||||
security_context {
|
||||
fs_group = 1000
|
||||
run_as_user = 1000
|
||||
}
|
||||
|
||||
container {
|
||||
name = "website"
|
||||
image = "nginx:stable-alpine"
|
||||
image_pull_policy = "Always"
|
||||
|
||||
resources {
|
||||
requests = {
|
||||
memory = "100Mi"
|
||||
}
|
||||
limits = {
|
||||
memory = "500Mi"
|
||||
}
|
||||
}
|
||||
|
||||
readiness_probe {
|
||||
http_get {
|
||||
path = "/"
|
||||
port = 8080
|
||||
}
|
||||
initial_delay_seconds = 5
|
||||
period_seconds = 10
|
||||
}
|
||||
|
||||
liveness_probe {
|
||||
http_get {
|
||||
path = "/"
|
||||
port = 8080
|
||||
}
|
||||
initial_delay_seconds = 5
|
||||
period_seconds = 10
|
||||
}
|
||||
|
||||
security_context {
|
||||
allow_privilege_escalation = false
|
||||
}
|
||||
|
||||
port {
|
||||
container_port = 8080
|
||||
name = "http"
|
||||
}
|
||||
volume_mount {
|
||||
name = "nginx-config"
|
||||
mount_path = "/etc/nginx/nginx.conf"
|
||||
sub_path = "nginx.conf"
|
||||
read_only = true
|
||||
}
|
||||
volume_mount {
|
||||
name = "nginx-config"
|
||||
mount_path = "/etc/nginx/conf.d/default.conf"
|
||||
sub_path = "default.conf"
|
||||
read_only = true
|
||||
}
|
||||
volume_mount {
|
||||
name = "website"
|
||||
mount_path = "/tmp/site"
|
||||
read_only = true
|
||||
}
|
||||
}
|
||||
volume {
|
||||
name = "nginx-config"
|
||||
config_map {
|
||||
name = kubernetes_config_map.nginx_config.metadata[0].name
|
||||
}
|
||||
}
|
||||
volume {
|
||||
name = "website"
|
||||
host_path {
|
||||
path = format("%s/%s", local.websites_path, each.key)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,239 +0,0 @@
|
||||
locals {
|
||||
wordpress_path = "${local.persistent_folder}/wordpress"
|
||||
wordpress_db_path = "${local.database_folder}/mysql.wordpress"
|
||||
wordpress_backup_path = "${local.persistent_folder}/backup.wordpress"
|
||||
}
|
||||
|
||||
resource "kubernetes_namespace" "wordpress" {
|
||||
metadata {
|
||||
annotations = {
|
||||
name = "wordpress"
|
||||
}
|
||||
|
||||
labels = {
|
||||
name = "wordpress"
|
||||
}
|
||||
|
||||
name = "wordpress"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# Setup MariaDB database
|
||||
#
|
||||
module "wordpress_database" {
|
||||
source = "./modules/k8s_mariadb"
|
||||
|
||||
namespace = kubernetes_namespace.wordpress.metadata[0].name
|
||||
app_name = "wordpress"
|
||||
|
||||
app_password = var.wordpress_mysql_password
|
||||
root_password = var.mysql_root_password
|
||||
|
||||
retention_days = local.local_backup_retention_days
|
||||
cron_schedule = local.wordpress_sql_backup_cron_schedule
|
||||
|
||||
database_folder = local.wordpress_db_path
|
||||
backup_folder = local.wordpress_backup_path
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# Setup rsync backup job to scaleway bucket
|
||||
#
|
||||
module "wordpress_backup" {
|
||||
source = "./modules/scw_backup_job"
|
||||
|
||||
namespace = kubernetes_namespace.wordpress.metadata[0].name
|
||||
app_name = "wordpress"
|
||||
|
||||
scaleway_organization_id = var.scaleway_organization_id
|
||||
scaleway_project_id = var.scaleway_organization_id
|
||||
access_key = scaleway_iam_api_key.backup_app_api.access_key
|
||||
secret_key = scaleway_iam_api_key.backup_app_api.secret_key
|
||||
bucket_name = scaleway_object_bucket.backup.name
|
||||
|
||||
retention_days = local.local_backup_retention_days
|
||||
cron_schedule = local.wordpress_files_backup_cron_schedule
|
||||
|
||||
source_folder = local.wordpress_path
|
||||
target_folder = local.wordpress_backup_path
|
||||
}
|
||||
|
||||
#
|
||||
# Gitea service, ingress, deployment and file backup job
|
||||
#
|
||||
resource "kubernetes_service_account" "wordpress_service_account" {
|
||||
|
||||
metadata {
|
||||
name = "wordpress-app-sa"
|
||||
namespace = kubernetes_namespace.wordpress.metadata[0].name
|
||||
}
|
||||
|
||||
automount_service_account_token = false
|
||||
}
|
||||
|
||||
|
||||
resource "kubernetes_service" "wordpress" {
|
||||
metadata {
|
||||
name = "http"
|
||||
namespace = kubernetes_namespace.wordpress.metadata[0].name
|
||||
}
|
||||
spec {
|
||||
port {
|
||||
port = 80
|
||||
target_port = "http"
|
||||
}
|
||||
selector = {
|
||||
app = "wordpress"
|
||||
}
|
||||
cluster_ip = "None"
|
||||
}
|
||||
}
|
||||
|
||||
resource "kubernetes_ingress_v1" "wordpress_ingress" {
|
||||
metadata {
|
||||
name = "wordpress-ingress"
|
||||
namespace = kubernetes_namespace.wordpress.metadata[0].name
|
||||
|
||||
annotations = {
|
||||
"kubernetes.io/ingress.class" = "public"
|
||||
"cert-manager.io/cluster-issuer" = "letsencrypt-prod"
|
||||
}
|
||||
}
|
||||
spec {
|
||||
tls {
|
||||
hosts = local.wordpress_fqdns
|
||||
secret_name = "wordpress-le-tls"
|
||||
}
|
||||
dynamic "rule" {
|
||||
for_each = local.wordpress_fqdns
|
||||
content {
|
||||
host = rule.value
|
||||
http {
|
||||
path {
|
||||
backend {
|
||||
service {
|
||||
name = "http"
|
||||
port {
|
||||
number = 80
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resource "kubernetes_deployment" "wordpress" {
|
||||
|
||||
depends_on = [module.wordpress_database]
|
||||
|
||||
metadata {
|
||||
name = "wordpress-app"
|
||||
namespace = kubernetes_namespace.wordpress.metadata[0].name
|
||||
}
|
||||
spec {
|
||||
selector {
|
||||
match_labels = {
|
||||
app = "wordpress"
|
||||
}
|
||||
}
|
||||
strategy {
|
||||
type = "RollingUpdate"
|
||||
}
|
||||
template {
|
||||
metadata {
|
||||
labels = {
|
||||
app = "wordpress"
|
||||
}
|
||||
}
|
||||
spec {
|
||||
service_account_name = kubernetes_service_account.wordpress_service_account.metadata[0].name
|
||||
|
||||
container {
|
||||
name = "wordpress"
|
||||
image = "wordpress:${local.wordpress_version}"
|
||||
image_pull_policy = "IfNotPresent"
|
||||
|
||||
resources {
|
||||
requests = {
|
||||
memory = "100Mi"
|
||||
}
|
||||
limits = {
|
||||
memory = "500Mi"
|
||||
}
|
||||
}
|
||||
|
||||
# readiness_probe {
|
||||
# http_get {
|
||||
# path = "/?nocache"
|
||||
# port = "http"
|
||||
# }
|
||||
# initial_delay_seconds = 20
|
||||
# period_seconds = 10
|
||||
# success_threshold = 1
|
||||
# failure_threshold = 5
|
||||
# }
|
||||
|
||||
# liveness_probe {
|
||||
# tcp_socket {
|
||||
# port = "http"
|
||||
# }
|
||||
# initial_delay_seconds = 30
|
||||
# period_seconds = 60
|
||||
# success_threshold = 1
|
||||
# failure_threshold = 10
|
||||
# }
|
||||
security_context {
|
||||
allow_privilege_escalation = false
|
||||
}
|
||||
|
||||
env {
|
||||
name = "WORDPRESS_DB_NAME"
|
||||
value = "wordpress"
|
||||
}
|
||||
env {
|
||||
name = "WORDPRESS_DB_HOST"
|
||||
value = "${module.wordpress_database.host}:${module.wordpress_database.port}"
|
||||
}
|
||||
env {
|
||||
name = "WORDPRESS_DB_USER"
|
||||
value_from {
|
||||
secret_key_ref {
|
||||
key = "username"
|
||||
name = module.wordpress_database.app_crendentials_name
|
||||
}
|
||||
}
|
||||
}
|
||||
env {
|
||||
name = "WORDPRESS_DB_PASSWORD"
|
||||
value_from {
|
||||
secret_key_ref {
|
||||
key = "password"
|
||||
name = module.wordpress_database.app_crendentials_name
|
||||
}
|
||||
}
|
||||
}
|
||||
port {
|
||||
container_port = 80
|
||||
name = "http"
|
||||
}
|
||||
volume_mount {
|
||||
mount_path = "/var/www/html"
|
||||
name = "persistent-storage"
|
||||
}
|
||||
}
|
||||
volume {
|
||||
name = "persistent-storage"
|
||||
host_path {
|
||||
path = local.wordpress_path
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
releases
|
||||
@@ -0,0 +1,39 @@
|
||||
# Created by https://www.toptal.com/developers/gitignore/api/visualstudiocode,hugo
|
||||
# Edit at https://www.toptal.com/developers/gitignore?templates=visualstudiocode,hugo
|
||||
|
||||
### Hugo ###
|
||||
# Generated files by hugo
|
||||
/public/
|
||||
/resources/_gen/
|
||||
/assets/jsconfig.json
|
||||
hugo_stats.json
|
||||
|
||||
# Executable may be added to repository
|
||||
hugo.exe
|
||||
hugo.darwin
|
||||
hugo.linux
|
||||
|
||||
# Temporary lock file while building
|
||||
/.hugo_build.lock
|
||||
|
||||
### VisualStudioCode ###
|
||||
.vscode/*
|
||||
!.vscode/settings.json
|
||||
!.vscode/tasks.json
|
||||
!.vscode/launch.json
|
||||
!.vscode/extensions.json
|
||||
!.vscode/*.code-snippets
|
||||
|
||||
# Local History for Visual Studio Code
|
||||
.history/
|
||||
|
||||
# Built Visual Studio Code Extensions
|
||||
*.vsix
|
||||
|
||||
### VisualStudioCode Patch ###
|
||||
# Ignore all local history of files
|
||||
.history
|
||||
.ionide
|
||||
.~lock.*.odt#
|
||||
|
||||
# End of https://www.toptal.com/developers/gitignore/api/visualstudiocode,hugo
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
date: '{{ .Date }}'
|
||||
draft: true
|
||||
title: '{{ replace .File.ContentBaseName "-" " " | title }}'
|
||||
---
|
||||
@@ -0,0 +1,368 @@
|
||||
baseURL: https://alexpires.me/
|
||||
languageCode: en-us
|
||||
title: Alexandre Pires
|
||||
theme: hugo-profile
|
||||
|
||||
outputs:
|
||||
home:
|
||||
- "HTML"
|
||||
- "RSS"
|
||||
- "JSON"
|
||||
page:
|
||||
- "HTML"
|
||||
- "RSS"
|
||||
|
||||
enableRobotsTXT: true
|
||||
|
||||
#services:
|
||||
#googleAnalytics:
|
||||
#id: G-MEASUREMENT_ID
|
||||
#disqus:
|
||||
#shortname: your-disqus-shortname
|
||||
|
||||
pagination:
|
||||
pagerSize: 3
|
||||
|
||||
markup:
|
||||
goldmark:
|
||||
renderer:
|
||||
unsafe: true
|
||||
|
||||
Menus:
|
||||
# main:
|
||||
# - identifier: blog
|
||||
# name: Blog
|
||||
# title: Blog posts
|
||||
# url: /blogs
|
||||
# weight: 1
|
||||
# - identifier: gallery
|
||||
# name: Gallery
|
||||
# title: Blog posts
|
||||
# url: /gallery
|
||||
# weight: 2
|
||||
#Dropdown menu
|
||||
# - identifier: dropdown
|
||||
# title: Example dropdown menu
|
||||
# name: Dropdown
|
||||
# weight: 3
|
||||
# - identifier: dropdown1
|
||||
# title: example dropdown 1
|
||||
# name: example 1
|
||||
# url: /#
|
||||
# parent: dropdown
|
||||
# weight: 1
|
||||
# - identifier: dropdown2
|
||||
# title: example dropdown 2
|
||||
# name: example 2
|
||||
# url: /#
|
||||
# parent: dropdown
|
||||
# weight: 2
|
||||
|
||||
params:
|
||||
title: "Alexandre Pires - Software/Systems Engineer"
|
||||
description: Text about my cool site
|
||||
# staticPath: "" # The path to serve the static files from
|
||||
favicon: "/fav.png"
|
||||
|
||||
# Whether to serve bootstrap css and js files from CDN or not. Can be set to true, "css" or "js" to choose between
|
||||
# serving both, only the css, or only the js files through the CDN. Any other value will make so that CDN is not used.
|
||||
# Note the lack of "" in true, it should be of boolean type.
|
||||
useBootstrapCDN: false
|
||||
|
||||
# If you want to load dynamically responsive images from Cloudinary
|
||||
# This requires your images to be uploaded + hosted on Cloudinary
|
||||
# Uncomment and change YOUR_CLOUD_NAME to the Cloud Name in your Cloudinary console
|
||||
# cloudinary_cloud_name: "YOUR_CLOUD_NAME"
|
||||
|
||||
# Whether to add mathjax support on all pages. Alternatively, you can opt-in per page by adding `mathjax: true` in the frontmatter.
|
||||
mathjax: false
|
||||
|
||||
# Whether the fade animations on the home page will be enabled
|
||||
animate: true
|
||||
|
||||
theme:
|
||||
disableThemeToggle: true
|
||||
defaultTheme: "dark"
|
||||
|
||||
font:
|
||||
fontSize: 1rem # default: 1rem
|
||||
fontWeight: 400 # default: 400
|
||||
lineHeight: 1.5 # default: 1.5
|
||||
textAlign: left # default: left
|
||||
|
||||
# color preference
|
||||
# When using hex codes for colors, quotations must be used along with the # sign
|
||||
# color:
|
||||
# textColor: "#343a40"
|
||||
# secondaryTextColor: "#6c757d"
|
||||
# textLinkColor: "#007bff"
|
||||
# backgroundColor: "#eaedf0"
|
||||
# secondaryBackgroundColor: "#64ffda1a"
|
||||
# primaryColor: "#007bff"
|
||||
# secondaryColor: "#f8f9fa"
|
||||
|
||||
# darkmode:
|
||||
# textColor: "#e4e6eb"
|
||||
# secondaryTextColor: "#b0b3b8"
|
||||
# textLinkColor: "#ffffff"
|
||||
# backgroundColor: "#18191a"
|
||||
# secondaryBackgroundColor: "#212529"
|
||||
# primaryColor: "#ffffff"
|
||||
# secondaryColor: "#212529"
|
||||
|
||||
# If you want to customize the menu, you can change it here
|
||||
navbar:
|
||||
align: ms-auto # Left: ms-auto | center: mx-auto | right: me-auto | Default: ms-auto
|
||||
# brandLogo: "/logo.png" # Logo for the brand | default is the favicon variable
|
||||
# showBrandLogo: false # Show brand logo in nav bar | default is true
|
||||
brandName: "Alexandre Pires" # Brand name for the brand | default is the title variable
|
||||
disableSearch: true
|
||||
# searchPlaceholder: "Search"
|
||||
stickyNavBar:
|
||||
enable: true
|
||||
showOnScrollUp: true
|
||||
enableSeparator: false
|
||||
menus:
|
||||
disableAbout: false
|
||||
disableExperience: false
|
||||
disableEducation: false
|
||||
disableProjects: false
|
||||
disableAchievements: false
|
||||
disableContact: false
|
||||
|
||||
# Hero
|
||||
hero:
|
||||
enable: true
|
||||
intro: "Welcome, my name is"
|
||||
title: "Alexandre Pires."
|
||||
subtitle: "Software/Systems Engineer"
|
||||
content: "A passionate IT professional with 10+ years of experience building tools on open-source tech, delivering solutions that drive business success."
|
||||
image: /images/hero.png
|
||||
bottomImage:
|
||||
enable: true
|
||||
# roundImage: true # Make hero image circular | default false
|
||||
button:
|
||||
enable: true
|
||||
name: "Resume"
|
||||
url: "cv.pdf"
|
||||
download: true
|
||||
newPage: false
|
||||
socialLinks:
|
||||
fontAwesomeIcons:
|
||||
- icon: fab fa-github
|
||||
url: https://github.com/a13labs/
|
||||
- icon: fab fa-linkedin-in
|
||||
url: https://www.linkedin.com/in/carlos-pires-b2597886/
|
||||
|
||||
# About
|
||||
about:
|
||||
enable: true
|
||||
title: "About Me"
|
||||
image: "/images/me.png"
|
||||
content: |-
|
||||
Over 10 years of experience in developing software and tools on top of open-source technologies, managing server infrastructures across architectures for high availability and performance, delivering business-driven solutions, and leading systems, projects, and teams across diverse IT environments.
|
||||
skills:
|
||||
enable: true
|
||||
title: "Here are a few skills I've been improving over the years:"
|
||||
items:
|
||||
- "Software development"
|
||||
- "Cloud platforms"
|
||||
- "Automation"
|
||||
- "Infrastructure as Code"
|
||||
- "Virtualization"
|
||||
- "Project management"
|
||||
- "Team leading and mentoring"
|
||||
|
||||
# Experience
|
||||
experience:
|
||||
enable: true
|
||||
# title: "Custom Name"
|
||||
items:
|
||||
- job: "Cloud Native/Platform Engineer"
|
||||
company: "KBC"
|
||||
companyUrl: "https://kbc.be"
|
||||
date: "Jul 2021 - present"
|
||||
info:
|
||||
enable: false
|
||||
content: "AWS engineer focused on building a Kubernetes-based platform. Part of a delivery-to-business team, responsible for designing, developing, and driving adoption of an EKS platform for business teams, with a strong focus on architectural design and building CI/CD solutions using GitHub Workflows."
|
||||
|
||||
- job: "DevOps/Linux System Engineer"
|
||||
company: "Siemens"
|
||||
companyUrl: "https://siemens.com"
|
||||
date: "Jan 2021 - Jun 2021"
|
||||
info:
|
||||
enable: false
|
||||
content: |
|
||||
Hired as a Linux System Engineer to develop and serve as a CI/CD Engineer for a new Azure DevOps-based Linux solution supporting the company's internal clients. Main responsibilities included using technologies like Docker, Ansible, Molecule, and Podman to design and build the core platform for clients to build, test, and deploy their software.
|
||||
|
||||
- job: "DevOps/Backend Lead Developer"
|
||||
company: "MovAI"
|
||||
companyUrl: "https://mov.ai"
|
||||
date: "Set 2019 - Dec 2020"
|
||||
info:
|
||||
enable: false
|
||||
content: |
|
||||
As the Backend/DevOps Lead, I was responsible for designing, implementing, and maintaining the CI/CD pipeline infrastructure. I worked closely with the Project Manager and R&D Manager to establish proper procedures and methodologies for a software development company, participated in the QA process, and led the design and implementation of the company's product deployment strategy. As the most senior developer, I played a key role in mentoring new team members, introducing best practices and design patterns, and helping to elevate the technical skills of the existing development team.
|
||||
|
||||
- job: "Linux System Engineer / DevOps Engineer"
|
||||
company: "ALPEGA Group"
|
||||
companyUrl: "https://www.alpegagroup.com/"
|
||||
date: "Set 2018 - Aug 2019"
|
||||
info:
|
||||
enable: false
|
||||
content: |
|
||||
Hired full-time as a Systems and DevOps Engineer to operate and enhance infrastructure, implement a new monitoring solution and deployment pipeline in AWS, enabling the adoption of DevOps practices and CI/CD. Played a key technical role in the company's 'lift-and-shift' migration project to AWS."
|
||||
|
||||
- job: "Linux System Engineer / Senior IT Manager"
|
||||
company: "HBD"
|
||||
companyUrl: "https:///hbd.com"
|
||||
date: "Mar 2013 - Aug 2018"
|
||||
info:
|
||||
enable: false
|
||||
content: |
|
||||
HBD is a private South African investment company focused on the sustainable and responsible development of Príncipe Island. With around 500 employees, HBD invests in social, agricultural, and infrastructure development, aiming to establish eco-resorts, including 5-star properties.
|
||||
Initially hired as a consultant, then brought on full-time to build the IT department from the ground up and restructure the company’s network and IT technology portfolio.
|
||||
|
||||
# Education
|
||||
education:
|
||||
enable: true
|
||||
# title: "Custom Name"
|
||||
index: false
|
||||
items:
|
||||
- title: "Bachelor of Science Robotics Engineering"
|
||||
school:
|
||||
name: "International University of Applied Sciences, Germany"
|
||||
url: "https://iu.org"
|
||||
date: "2021 - present"
|
||||
GPA: ""
|
||||
content:
|
||||
- title: "Bachelor of Science Computer Science Engineering"
|
||||
school:
|
||||
name: "Universidade Aberta, Portugal"
|
||||
url: "https://portal.uab.pt/"
|
||||
date: "2016 - 2023"
|
||||
GPA: "4 out of 5.0"
|
||||
content: |-
|
||||
I Publiced one papers in the University Journal on parallel computing.
|
||||
- [Proposal for an optimized variant of A* Algorithm for multi-core systems ](https://journals.uab.pt/index.php/rcc/article/view/297)
|
||||
- title: "High School"
|
||||
school:
|
||||
name: "Escola secundária de Anadia"
|
||||
url: "https://aeanadia.pt/"
|
||||
GPA: "3 out of 5.0"
|
||||
|
||||
# Achievements
|
||||
achievements:
|
||||
enable: false
|
||||
# title: "Custom Name"
|
||||
items:
|
||||
- title: Google kickstart runner
|
||||
content: I solved all problems with optimal solution.
|
||||
url: https://example.com
|
||||
image: /images/achievement.jpg
|
||||
|
||||
# projects
|
||||
projects:
|
||||
enable: false
|
||||
# title: "Custom Name"
|
||||
items:
|
||||
- title: Hugo Profile
|
||||
content: A highly customizable and mobile first Hugo template for personal portfolio and blog.
|
||||
image: /images/projects/profile.png
|
||||
featured:
|
||||
name: Demo
|
||||
link: https://hugo-profile.netlify.app
|
||||
badges:
|
||||
- "Hugo"
|
||||
- "Bootstrap"
|
||||
- "Javascript"
|
||||
links:
|
||||
- icon: fa fa-envelope
|
||||
url: mailto:?subject=Hugo%20Profile%20Template&body=Check%20it%20out:%20https%3a%2f%2fhugo-profile.netlify.app%2fblog%2fmarkdown-syntax%2f
|
||||
- icon: fab fa-github
|
||||
url: https://github.com/gurusabarish/hugo-profile
|
||||
- icon: fab fa-twitter
|
||||
url: https://twitter.com/intent/tweet?text=Check+it+out:&url=https%3A%2F%2Fgithub.com%2Fgurusabarish%2Fhugo-profile
|
||||
|
||||
- title: Image Converter
|
||||
content: A web app to convert image to pdf, png to jpg, png to jpg and png to webp without database using django.
|
||||
image: /images/projects/converter.jpg
|
||||
featured:
|
||||
name: Demo
|
||||
link: https://django-converter.herokuapp.com
|
||||
badges:
|
||||
- "Django"
|
||||
- "Bootstrap"
|
||||
links:
|
||||
- icon: fab fa-github
|
||||
url: https://github.com/gurusabarish/converter
|
||||
|
||||
- title: Hugo Profile V2
|
||||
content: A clean and simple Hugo template for personal portfolio and blog.
|
||||
image: /images/projects/profile2.jpg
|
||||
featured:
|
||||
name: Demo V2
|
||||
link: https://hugo-profile-2.netlify.app
|
||||
badges:
|
||||
- "Hugo"
|
||||
- "Bootstrap"
|
||||
- "Javascript"
|
||||
links:
|
||||
- icon: fab fa-github
|
||||
url: https://github.com/gurusabarish/HugoProfileV2
|
||||
|
||||
#Contact
|
||||
contact:
|
||||
enable: true
|
||||
# title: "Custom Name"
|
||||
content: My inbox is always open. Whether you have a question or just want to say hi, I’ll try my best to get back to you!
|
||||
btnName: Mail me
|
||||
btnLink: mailto:c.alexandre.pires@alexpires.me
|
||||
# formspree:
|
||||
# enable: true # `contact.email` value will be ignored
|
||||
# formId: abcdefgh # Take it from your form's endpoint, like 'https://formspree.io/f/abcdefgh'
|
||||
# emailCaption: "Enter your email address"
|
||||
# messageCaption: "Enter your message here"
|
||||
# messageRows: 5
|
||||
|
||||
footer:
|
||||
recentPosts:
|
||||
path: "blogs"
|
||||
count: 3
|
||||
title: Recent Posts
|
||||
enable: false
|
||||
disableFeaturedImage: false
|
||||
socialNetworks:
|
||||
github: https://github.com/a13labs/
|
||||
linkedin: https://www.linkedin.com/in/carlos-pires-b2597886/
|
||||
|
||||
# List pages like blogs and posts
|
||||
listPages:
|
||||
disableFeaturedImage: false
|
||||
|
||||
# Single pages like blog and post
|
||||
singlePages:
|
||||
socialShare: true
|
||||
readTime:
|
||||
enable: true
|
||||
content: "min read"
|
||||
scrollprogress:
|
||||
enable: true
|
||||
tags:
|
||||
openInNewTab: true
|
||||
|
||||
# For translations
|
||||
terms:
|
||||
read: "Read"
|
||||
toc: "Table Of Contents"
|
||||
copyright: "All rights reserved"
|
||||
pageNotFound: "Page not found"
|
||||
emailText: "Check out this site"
|
||||
|
||||
datesFormat:
|
||||
article: "Jan 2, 2006"
|
||||
articleList: "Jan 2, 2006"
|
||||
articleRecent: "Jan 2, 2006"
|
||||
|
||||
#customScripts: -| # You can add custom scripts which will be added before </body> tag
|
||||
# <script type="text/javascript"><!-- any script here --></script>
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
After Width: | Height: | Size: 23 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 319 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 442 KiB |
Submodule
+1
Submodule websites/themes/hugo-profile added at b8c83aff4c
Reference in New Issue
Block a user