The steps to DevOps challenge:
- Create APP and containerize it and push that to public docker hub.
- Launch Jenkins through Docker Compose
- Create 3 LXC Container for k3s
- Create k3s Cluster on those
- Deploy the hit_record APP with k3s
$ docker build -f Dockerfile -t <DOCKERHUB_USER>/hit_record:latest .
$ docker push <DOCKERHUB_USER>/hit_record:latest
Github Action:
name: Docker Image CI
on:
release:
types: [published]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Build the Docker image
run: docker build . --file Dockerfile --tag ${{ secrets.DOCKERHUB_USERNAME }}/hitrecord:latest
-
name: Login to Docker Hub
uses: docker/login-action@v1
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Push the image
run: docker push ${{ secrets.DOCKERHUB_USERNAME }}/hitrecord:latest
Needed to set the secret with api token collected from DOCKERHUB. This action do work for tag release published.
Need docker-compose.
$ cd JenkinsServer
$ docker-compose up -d
This will start the Jenkins Server.
$ sudo apt install lxd zfsutils-linux
Configure LXD
$ lxd init
$ lxc launch ubuntu:20.04 k1
$ lxc launch ubuntu:20.04 k2
$ lxc launch ubuntu:20.04 k3
$ git clone git@github.com:k3s-io/k3s-ansible.git;cd k3s-ansible;
First create a new directory based on the sample directory within the inventory directory:
cp -R inventory/sample inventory/k3s-cluster-inventory
Second, edit inventory/k3s-cluster-inventory/hosts.ini to match the system information gathered above. For example:
[master]
192.168.168.100
[node]
192.168.168.[101:102]
[k3s_cluster:children]
master
node
group_vars
---
k3s_version: v1.23.4+k3s1
ansible_user: root
systemd_dir: /etc/systemd/system
master_ip: "{{ hostvars[groups['master'][0]]['ansible_host'] | default(groups['master'][0]) }}"
extra_server_args: ""
extra_agent_args: ""
Also, to use the hosts created by LXC, needed to set ssh key to those and enable ssh properly.
Let's create:
ansible-playbook site.yml -i inventory/k3s-cluster-inventory/hosts.ini
It will create the cluster.
Need ingress
helm install hitrecord-ingress nginx-stable/nginx-ingress
$ cd deployment
$ kubectl apply -f .
This will deploy the application.
# kubectl apply -f .
deployment.apps/hit-record-api-v1-deployment created
service/hit-record-api-v1-service created
deployment.apps/hit-record-api-v2-deployment created
service/hit-record-api-v2-service created
configmap/hit-record-configmap created
ingress.networking.k8s.io/hitrecord-ingress created
deployment.apps/redis-deployment created
service/redis-service created
Need helm to install linkerd and inject linkerd
$ curl --proto '=https' --tlsv1.2 -sSfL https://run.linkerd.io/install | sh
$ cat hit_record_api_v1_deployment.yaml| linkerd inject - | kubectl apply -f -
$ cat hit_record_api_v2_deployment.yaml| linkerd inject - | kubectl apply -f -
Visualize
$ linkerd viz install | kubectl apply -f -
$ linkerd viz dashboard
% kubectl get pods
NAME READY STATUS RESTARTS AGE
hit-record-api-v1-deployment-68b97bb87-wlth2 1/1 Running 0 3m22s
hit-record-api-v2-deployment-767d67bb4d-cwckk 1/1 Running 0 3m21s
hit-record-release-nginx-ingress-64f777454d-6ctj2 1/1 Running 2 (10h ago) 18h
redis-deployment-756b4b8956-hbqmk 1/1 Running 0 3m21s
As I was in need to deploy v1 to workernode1 and v2 to workernode2, rewritten deployment file:
apiVersion: apps/v1
kind: Deployment
metadata:
name: hit-record-api-v1-deployment
labels:
app: hit-record-api-v1
spec:
replicas: 1
selector:
matchLabels:
app: hit-record-api-v1
template:
metadata:
labels:
app: hit-record-api-v1
spec:
nodeName: workernode1
containers:
- name: hit-record-api-v1
image: fahadahammed/hit_record:latest
ports:
- containerPort: 22000
env:
- name: API_VERSION
valueFrom:
configMapKeyRef:
name: hit-record-configmap
key: hit_record_api_v1
- name: REDIS_HOST
valueFrom:
configMapKeyRef:
name: hit-record-configmap
key: redis_host
Let's try API access with version:
% curl http://hitrecord.example.com/api/v1/
{
"datetime": "Sun, 06 Mar 2022 15:09:29 GMT",
"hit_count": 1,
"hostname": "hit-record-api-v1-deployment-68b97bb87-j8v6t",
"msg": "Welcome to hit_record! I am going to record the hit count in redis.",
"version": "v1"
}
% curl http://hitrecord.example.com/api/v2/
{
"datetime": "Sun, 06 Mar 2022 15:09:32 GMT",
"hit_count": 2,
"hostname": "hit-record-api-v2-deployment-767d67bb4d-sc5zm",
"msg": "Welcome to hit_record! I am going to record the hit count in redis.",
"version": "v2"
}
I have made the routing based on api version on url.