Skip to content

Commit d474224

Browse files
committed
Updated blog structure
1 parent 7c25625 commit d474224

File tree

1 file changed

+90
-36
lines changed
  • adminforth/documentation/blog/2025-11-04-k3s-ec2-deployment

1 file changed

+90
-36
lines changed

adminforth/documentation/blog/2025-11-04-k3s-ec2-deployment/index.md

Lines changed: 90 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -129,9 +129,19 @@ locals {
129129
subnet_b_cidr = "10.0.11.0/24"
130130
az_a = "us-west-2a"
131131
az_b = "us-west-2b"
132-
app_name = "<your_app_name>"
132+
app_name = <your_app_name>
133133
app_source_code_path = "../../"
134134
ansible_dir = "../ansible/playbooks"
135+
app_files = fileset(local.app_source_code_path, "**")
136+
137+
image_tag = sha256(join("", [
138+
for f in local.app_files :
139+
try(filesha256("${local.app_source_code_path}/${f}"), "")
140+
if length(regexall("^deploy/", f)) == 0
141+
&& length(regexall("^\\.vscode/", f)) == 0
142+
&& length(regexall("^node_modules/", f)) == 0
143+
&& length(regexall("^\\.gitignore", f)) == 0
144+
]))
135145
136146
ingress_ports = [
137147
{ from = 22, to = 22, protocol = "tcp", desc = "SSH" },
@@ -142,7 +152,7 @@ locals {
142152
}
143153
144154
provider "aws" {
145-
region = local.aws_region
155+
region = local.aws_region
146156
profile = "myaws"
147157
}
148158
@@ -182,9 +192,12 @@ resource "aws_instance" "ec2_instance" {
182192
183193
# prevent accidental termination of ec2 instance and data loss
184194
lifecycle {
185-
#create_before_destroy = true #uncomment in production
195+
create_before_destroy = true #uncomment in production
186196
#prevent_destroy = true #uncomment in production
187197
ignore_changes = [ami]
198+
replace_triggered_by = [
199+
null_resource.docker_build_and_push
200+
]
188201
}
189202
190203
root_block_device {
@@ -210,6 +223,12 @@ EOF
210223
resource "null_resource" "wait_ssh" {
211224
depends_on = [aws_instance.ec2_instance]
212225
226+
triggers = (
227+
{
228+
instance_id = aws_instance.ec2_instance.id
229+
}
230+
)
231+
213232
provisioner "local-exec" {
214233
command = <<EOT
215234
bash -c '
@@ -227,9 +246,14 @@ resource "null_resource" "ansible_provision" {
227246
depends_on = [
228247
aws_instance.ec2_instance,
229248
local_file.ansible_inventory,
230-
null_resource.wait_ssh
249+
null_resource.wait_ssh,
250+
local_file.image_tag
231251
]
232252
253+
triggers = {
254+
instance_id = aws_instance.ec2_instance.id
255+
}
256+
233257
provisioner "local-exec" {
234258
interpreter = ["/bin/bash", "-c"]
235259
@@ -240,6 +264,7 @@ resource "null_resource" "ansible_provision" {
240264
EOT
241265
}
242266
}
267+
243268
```
244269

245270
> 👆 Replace `<your_app_name>` with your app name (no spaces, only underscores or letters)
@@ -261,33 +286,43 @@ resource "aws_ecr_repository" "app_repo" {
261286
data "aws_caller_identity" "current" {}
262287
263288
resource "null_resource" "docker_build_and_push" {
264-
265289
depends_on = [aws_ecr_repository.app_repo]
266290
291+
triggers = {
292+
image_tag = local.image_tag
293+
}
294+
267295
provisioner "local-exec" {
268296
command = <<-EOT
269297
set -e
270298
unset DOCKER_HOST
271-
299+
272300
REPO_URL="${aws_ecr_repository.app_repo.repository_url}"
273301
ACCOUNT_ID="${data.aws_caller_identity.current.account_id}"
274302
REGION="${local.aws_region}"
275-
303+
TAG="${local.image_tag}"
304+
276305
echo "LOG: Logging in to ECR..."
277306
aws ecr get-login-password --region $${REGION} | docker login --username AWS --password-stdin $${ACCOUNT_ID}.dkr.ecr.$${REGION}.amazonaws.com
278307
279308
echo "LOG: Building Docker image..."
280-
docker -H unix:///var/run/docker.sock build --pull -t $${REPO_URL}:latest ${local.app_source_code_path}
309+
docker build --pull -t $${REPO_URL}:$${TAG} ${local.app_source_code_path}
281310
282311
echo "LOG: Pushing image to ECR..."
283-
docker -H unix:///var/run/docker.sock push $${REPO_URL}:latest
312+
docker push $${REPO_URL}:$${TAG}
284313
285-
echo "LOG: Build and push complete."
314+
echo "LOG: Build and push complete. TAG=$${TAG}"
286315
EOT
287316
288317
interpreter = ["/bin/bash", "-c"]
289318
}
290319
}
320+
321+
resource "local_file" "image_tag" {
322+
depends_on = [null_resource.docker_build_and_push]
323+
content = local.image_tag
324+
filename = "${path.module}/image_tag.txt"
325+
}
291326
```
292327

293328
This file contains a script that builds the Docker image locally. This is done for more flexible deployment. When changing the program code, there is no need to manually update the image on EC2 or in the repository. It is updated automatically with each terraform apply. Below is a table showing the time it takes to build this image from scratch and with minimal changes.
@@ -445,7 +480,7 @@ you need to create a file `Chart.yaml` in it
445480

446481
```yaml title="deploy/helm/helm_charts/Chart.yaml"
447482
apiVersion: v2
448-
name: myadmin
483+
name: myadmink3s # SET YOUR APP NAME
449484
description: Helm chart for myadmin app
450485
version: 0.1.0
451486
appVersion: "1.0.0"
@@ -454,11 +489,12 @@ appVersion: "1.0.0"
454489
And `values.yaml`
455490

456491
```yaml title="deploy/helm/helm_charts/values.yaml"
457-
appName: myadmin
492+
appName: myadmink3s # SET YOUR APP NAME LIKE IN Chart.yaml
493+
appNameSpace: myadmin # SET YOUR APP NAMESPACE
458494
containerPort: 3500
459495
servicePort: 80
460496
adminSecret: "your_secret"
461-
ecrImageFull: 735356255780.dkr.ecr.us-west-2.amazonaws.com/myadmink3s:latest ## <-- change to your repo url
497+
ecrImageFull: ""
462498
```
463499
After this create .../deploy/helm/helm_charts/templates folder
464500

@@ -471,7 +507,7 @@ apiVersion: apps/v1
471507
kind: Deployment
472508
metadata:
473509
name: {{ .Values.appName }}-deployment
474-
namespace: {{ .Values.appName }}
510+
namespace: {{ .Values.appNameSpace }}
475511
spec:
476512
replicas: 1
477513
selector:
@@ -499,7 +535,7 @@ apiVersion: networking.k8s.io/v1
499535
kind: Ingress
500536
metadata:
501537
name: {{ .Values.appName }}-ingress
502-
namespace: {{ .Values.appName }}
538+
namespace: {{ .Values.appNameSpace }}
503539
spec:
504540
rules:
505541
- http:
@@ -520,7 +556,7 @@ apiVersion: v1
520556
kind: Service
521557
metadata:
522558
name: {{ .Values.appName }}-service
523-
namespace: {{ .Values.appName }}
559+
namespace: {{ .Values.appNameSpace }}
524560
spec:
525561
type: ClusterIP
526562
selector:
@@ -552,31 +588,38 @@ Then the file `playbook.yaml`
552588
kubeconfig_path: /etc/rancher/k3s/k3s.yaml
553589
helm_url: https://get.helm.sh/helm-v3.12.3-linux-amd64.tar.gz
554590
helm_dest: /usr/local/bin/helm
555-
app_name: myadmin
556-
app_namespace: myadmin
591+
app_name: myadmink3s # <-- CHANGE TO YOUR APP NAME LIKE IN main.tf local.app_name
592+
app_namespace: myadmin # <-- CHANGE TO YOUR APP NAMESPACE
593+
aws_account_id: "735356255780" # <-- CHANGE TO YOUR AWS ACCOUNT ID
557594
chart_path: /home/ubuntu/{{app_name}}/helm_charts
558595
559596
tasks:
560597
598+
- name: Read Docker image tag (local)
599+
ansible.builtin.set_fact:
600+
image_tag: "{{ lookup('file', '../../terraform/image_tag.txt') }}"
601+
delegate_to: localhost
602+
561603
- name: Install unzip
562-
apt:
604+
ansible.builtin.apt:
563605
name: unzip
564606
state: present
565607
update_cache: true
566608
567609
- name: Download AWS CLI v2
568-
get_url:
610+
ansible.builtin.get_url:
569611
url: "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip"
570612
dest: /tmp/awscliv2.zip
613+
mode: '0644'
571614
572615
- name: Unzip AWS CLI
573-
unarchive:
616+
ansible.builtin.unarchive:
574617
src: /tmp/awscliv2.zip
575618
dest: /tmp
576619
remote_src: true
577620
578621
- name: Install AWS CLI
579-
command: /tmp/aws/install --update
622+
ansible.builtin.command: /tmp/aws/install --update
580623
args:
581624
creates: /usr/local/bin/aws
582625
@@ -594,25 +637,34 @@ Then the file `playbook.yaml`
594637
- ca-certificates
595638
state: present
596639
640+
- name: Download k3s installation script
641+
ansible.builtin.get_url:
642+
url: https://get.k3s.io
643+
dest: /tmp/install_k3s.sh
644+
mode: '0700'
645+
597646
- name: Install k3s
598-
ansible.builtin.shell: |
599-
curl -sfL https://get.k3s.io | INSTALL_K3S_VERSION={{ k3s_version }} sh -
647+
ansible.builtin.command: /tmp/install_k3s.sh
648+
environment:
649+
INSTALL_K3S_VERSION: "{{ k3s_version }}"
600650
args:
601651
creates: /usr/local/bin/k3s
602652
603653
- name: Get ECR token
604-
command: aws ecr get-login-password --region us-west-2
654+
ansible.builtin.command: aws ecr get-login-password --region us-west-2
605655
register: ecr_token
656+
changed_when: false
606657
607658
- name: Configure K3s registry for ECR
608-
copy:
659+
ansible.builtin.copy:
609660
dest: /etc/rancher/k3s/registries.yaml
610661
content: |
611662
configs:
612663
"735356255780.dkr.ecr.us-west-2.amazonaws.com":
613664
auth:
614665
username: AWS
615666
password: "{{ ecr_token.stdout }}"
667+
mode: '0600'
616668
617669
- name: Restart k3s to apply registry changes
618670
ansible.builtin.systemd:
@@ -690,29 +742,31 @@ Then the file `playbook.yaml`
690742
691743
- name: Copy Helm chart to server
692744
ansible.builtin.copy:
693-
src: "../../helm/helm_charts"
694-
dest: /home/ubuntu/{{app_name}}
745+
src: "../../helm/helm_charts"
746+
dest: /home/ubuntu/{{ app_name }}
695747
owner: ubuntu
696748
group: ubuntu
697749
mode: '0755'
698750
force: true
699751
700-
- name: Ensure {{app_namespace}} namespace exists
752+
- name: Ensure namespace exists - {{ app_namespace }}
701753
kubernetes.core.k8s:
702754
api_version: v1
703755
kind: Namespace
704-
name: myadmin
756+
name: "{{ app_namespace }}"
705757
kubeconfig: "{{ kubeconfig_path }}"
706758
707-
- name: Deploy {{app_name}} stack via Helm
759+
- name: Deploy stack via Helm - {{ app_name }}
708760
kubernetes.core.helm:
709-
name: myadmin
710-
chart_ref: /home/ubuntu/{{app_name}}/helm_charts
711-
release_namespace: "{{app_namespace}}"
761+
name: "{{ app_namespace }}"
762+
chart_ref: /home/ubuntu/{{ app_name }}/helm_charts
763+
release_namespace: "{{ app_namespace }}"
712764
kubeconfig: "{{ kubeconfig_path }}"
713765
create_namespace: false
714-
values_files:
715-
- /home/ubuntu/{{app_name}}/helm_charts/values.yaml
766+
values_files:
767+
- /home/ubuntu/{{ app_name }}/helm_charts/values.yaml
768+
values:
769+
ecrImageFull: "{{ aws_account_id }}.dkr.ecr.us-west-2.amazonaws.com/{{ app_name }}:{{ image_tag }}"
716770
force: true
717771
atomic: false
718772
```

0 commit comments

Comments
 (0)