{"id":29089452,"url":"https://github.com/ikajdan/devops-course-tasks","last_synced_at":"2026-05-05T14:02:33.048Z","repository":{"id":300298081,"uuid":"1005799100","full_name":"ikajdan/devops-course-tasks","owner":"ikajdan","description":"Terraform infrastructure tasks for a DevOps course","archived":false,"fork":false,"pushed_at":"2025-07-26T22:27:38.000Z","size":42,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-01-20T10:54:03.646Z","etag":null,"topics":["aws","cicd","continuous-integration","devops","jenkins","kubernetes","terraform"],"latest_commit_sha":null,"homepage":"","language":"HCL","has_issues":false,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ikajdan.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2025-06-20T20:57:11.000Z","updated_at":"2025-07-26T22:23:27.000Z","dependencies_parsed_at":"2025-07-21T22:08:00.481Z","dependency_job_id":"82872fc8-a056-4986-bb6b-ca173b96f5bb","html_url":"https://github.com/ikajdan/devops-course-tasks","commit_stats":null,"previous_names":["ikajdan/devops-course-tasks"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/ikajdan/devops-course-tasks","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ikajdan%2Fdevops-course-tasks","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ikajdan%2Fdevops-course-tasks/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ikajdan%2Fdevops-course-tasks/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ikajdan%2Fdevops-course-tasks/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ikajdan","download_url":"https://codeload.github.com/ikajdan/devops-course-tasks/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ikajdan%2Fdevops-course-tasks/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32652474,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-05T11:29:49.557Z","status":"ssl_error","status_checked_at":"2026-05-05T11:29:48.587Z","response_time":54,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["aws","cicd","continuous-integration","devops","jenkins","kubernetes","terraform"],"created_at":"2025-06-28T04:01:57.930Z","updated_at":"2026-05-05T14:02:33.042Z","avatar_url":"https://github.com/ikajdan.png","language":"HCL","funding_links":[],"categories":[],"sub_categories":[],"readme":"# DevOps Course Tasks\n\nThis repository contains infrastructure tasks for a DevOps course.\n\n## Usage\n\nRun `make` to deploy the infrastructure. The Makefile includes the following targets:\n\n- `format`: Formats Terraform files\n- `check`: Checks formatting of Terraform files\n- `validate`: Validates Terraform files\n- `init`: Initializes Terraform\n- `plan`: Creates an execution plan\n- `apply`: Applies the Terraform configuration\n- `destroy`: Destroys the infrastructure\n\n## CI/CD\n\nGitHub Actions runs on push, PR, and manual triggers:\n\n- Checks formatting\n- Plans infrastructure\n- Applies to AWS (on main)\n\n## Notes\n\n- State is stored in an S3 bucket\n- CI assumes an IAM role via OIDC\n\n## Architecture\n\nThe architecture consists of a VPC with two availability zones (AZ1 and AZ2), each containing public and private subnets. The bastion host is in the public subnet of AZ2, while the public VM is in the public subnet of AZ1. The private VMs are in their respective private subnets.\n\n![resource_map](https://github.com/user-attachments/assets/e256d21a-158a-44f1-a52c-9068112e3635)\n\nThe following diagram illustrates the network connections and routing tables.\n\n```mermaid\nflowchart TD\n  VPC[\"VPC: main-vpc\"]\n\n  subgraph Subnets\n    PUB1[\"public-subnet-1 (eu-west-1a)\"]\n    PRIV1[\"private-subnet-1 (eu-west-1a)\"]\n    PUB2[\"public-subnet-2 (eu-west-1b)\"]\n    PRIV2[\"private-subnet-2 (eu-west-1b)\"]\n  end\n\n  subgraph RouteTables\n    PRTRT[\"private-rt\"]\n    PUBRT[\"public-rt\"]\n  end\n\n  subgraph NetworkConnections\n    IGW[\"main-igw (Internet Gateway)\"]\n    NAT[\"main-nat (NAT Gateway)\"]\n  end\n\n  VPC --\u003e PUB1\n  VPC --\u003e PRIV1\n  VPC --\u003e PUB2\n  VPC --\u003e PRIV2\n\n  PUB1 --\u003e PUBRT\n  PUB2 --\u003e PUBRT\n  PRIV1 --\u003e PRTRT\n  PRIV2 --\u003e PRTRT\n\n  PUBRT --\u003e IGW\n  PRTRT --\u003e NAT\n```\n\nThe following table lists the VMs created in the infrastructure.\n\n| Name             | Instance ID            | AZ         | Public IP        | Private IP     | Security Group  |\n|------------------|------------------------|------------|------------------|----------------|-----------------|\n| bastion-host     | i-054a6efc895bb2e65    | eu-west-1a | 34.248.59.113    | 10.0.1.155     | bastion-sg      |\n| public-vm        | i-07934d09c5ef6492d    | eu-west-1b | 3.254.135.50     | 10.0.2.48      | public-vm-sg    |\n| private-vm-a     | i-01316392d209f28fb    | eu-west-1a | —                | 10.0.101.26    | private-vm-sg   |\n| private-vm-b     | i-06deb0195ce41bde2    | eu-west-1b | —                | 10.0.102.55    | private-vm-sg   |\n\n## Connectivity Testing\n\nEach VM has been tested for connectivity as follows.\n\n1. Bastion VM\n\n   ```\n   ssh -A ec2-user@34.248.59.113\n   [ec2-user@ip-10-0-1-155 ~]$ curl -s ifconfig.me      # Via IGW\n   34.248.59.113\n   [ec2-user@ip-10-0-1-155 ~]$ ssh ec2-user@10.0.2.48   # Connects to public VM\n   [ec2-user@ip-10-0-1-155 ~]$ ssh ec2-user@10.0.101.26 # Connects to private VM A\n   [ec2-user@ip-10-0-1-155 ~]$ ssh ec2-user@10.0.102.55 # Connects to private VM B\n   ```\n\n2. Public VM\n\n   ```\n   ssh -A ec2-user@3.254.135.50\n   [ec2-user@ip-10-0-2-82 ~]$ curl -s ifconfig.me       # Via IGW\n   3.254.135.50\n   [ec2-user@ip-10-0-1-155 ~]$ ssh ec2-user@10.0.101.26 # Does not connect to private    VM A\n   [ec2-user@ip-10-0-1-155 ~]$ ssh ec2-user@10.0.102.55 # Does not connect to private    VM B\n   ```\n\n3. Private VM A\n\n   ```\n   ssh -A ec2-user@34.248.59.113                           # Connects to bastion\n   [ec2-user@ip-10-0-1-155 ~]$ ssh -A ec2-user@10.0.101.26 # Connects to private VM A\n   [ec2-user@ip-10-0-101-26 ~]$ curl ifconfig.me           # Via NAT\n   63.35.144.83\n   [ec2-user@ip-10-0-101-26 ~]$ ssh ec2-user@10.0.2.48     # Connects to public VM\n   [ec2-user@ip-10-0-101-26 ~]$ ssh ec2-user@10.0.102.55   # Does not connect to    private VM B\n   ```\n\n4. Private VM B\n\n   ```\n   ssh -A ec2-user@34.248.59.113                           # Connects to bastion\n   [ec2-user@ip-10-0-1-155 ~]$ ssh -A ec2-user@10.0.102.55 # Connects to private VM B\n   [ec2-user@ip-10-0-101-26 ~]$ curl ifconfig.me           # Via NAT\n   63.35.144.83\n   [ec2-user@ip-10-0-101-26 ~]$ ssh ec2-user@10.0.2.48     # Connects to public VM\n   [ec2-user@ip-10-0-101-26 ~]$ ssh ec2-user@10.0.101.26   # Does not connect to    private VM A\n   ```\n\n## K3s Cluster Setup\n\nInstall and configure a lightweight Kubernetes (k3s) cluster on AWS EC2 instances provisioned by Terraform.\n\nThe following table lists the private and public IP addresses of the EC2 instances:\n\n| Name         | Private IP     | Public IP        |\n|--------------|----------------|------------------|\n| public-vm    | 10.0.2.175     | 3.250.121.94     |\n| bastion-host | 10.0.1.117     | 3.253.17.168     |\n| private-vm-a | 10.0.101.123   | None             |\n| private-vm-b | 10.0.102.39    | None             |\n\n### Master Node Setup (private-vm-a)\n\n#### 1. SSH from Bastion\n\n```sh\nssh -A ubuntu@3.253.17.168\nssh ubuntu@10.0.101.123\n```\n\n#### 2. Install k3s Server\n\n```sh\ncurl -sfL https://get.k3s.io | sh -\n```\n\n#### 3. Get Cluster Token\n\n```sh\nsudo cat /var/lib/rancher/k3s/server/node-token\n```\n\n#### 4. Verify Node\n\n```sh\nsudo k3s kubectl get nodes\n```\n\nYou should see output similar to:\n\n```\nubuntu@ip-10-0-101-123:~$ sudo k3s kubectl get nodes\nNAME              STATUS   ROLES                  AGE   VERSION\nip-10-0-101-123   Ready    control-plane,master   1m    v1.32.5+k3s1\n```\n\n### Worker Node Setup (private-vm-b)\n\n#### 1. SSH from Bastion\n\n```sh\nssh ubuntu@10.0.102.39\n```\n\n#### 2. Install k3s Agent\n\n```sh\ncurl -sfL https://get.k3s.io | K3S_URL=https://10.0.101.123:6443 K3S_TOKEN=\u003ctoken\u003e sh -\n```\n\nReplace `\u003ctoken\u003e` with the value from the master node.\n\n### Bastion Host Setup\n\n##### 1. SSH into the Bastion Host\n\n```sh\nssh -A ubuntu@3.253.17.168\n```\n\n#### 2. Install `kubectl`\n\n```sh\ncurl -LO \"https://dl.k8s.io/release/$(curl -sL https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl\"\nchmod +x kubectl\nsudo mv kubectl /usr/local/bin/\n```\n\n#### 3. Copy the Kubeconfig to the Bastion Host\n\nThe file is located at `/etc/rancher/k3s/k3s.yaml` on the master node.\n\n#### 4. Update the Kubeconfig\n\n```sh\nsed -i 's/127.0.0.1/10.0.101.123/' ~/k3s.yaml\n```\n\n#### 5. Verify `kubectl` Configuration\n\n```sh\nexport KUBECONFIG=~/k3s.yaml\nkubectl get nodes\n```\n\nYou should see output similar to:\n\n```\nNAME              STATUS   ROLES                  AGE   VERSION\nip-10-0-101-123   Ready    control-plane,master   2m    v1.32.5+k3s1\nip-10-0-102-39    Ready    worker                 1m    v1.32.5+k3s1\n```\n\n### Access from Local Machine\n\nTo access the k3s cluster from your local machine, you need to set up an SSH tunnel.\n\n#### 1. Start SSH Tunnel\n\n```sh\nssh -i bastion_ssh_key.pem -L 6443:10.0.101.123:6443 ubuntu@3.253.17.168\n```\n\n#### 2. Copy Kubeconfig\n\n```sh\nscp -i bastion_ssh_key.pem ubuntu@3.253.17.168:/home/ubuntu/k3s.yaml ~/.kube/config\n```\n\n#### 3. Update and Use Kubeconfig\n\nEdit `~/.kube/config`:\n\n```yaml\nserver: https://localhost:6443\n```\n\nThen run:\n\n```sh\nkubectl get nodes\nkubectl get pods\n```\n\n## Jenkins Installation and Configuration on Minikube\n\nDeploy Jenkins using Helm on a local Minikube cluster. Verify the setup with a basic \"Hello World\" freestyle job and configure Jenkins using JCasC.\n\n### Prerequisites\n\n* [Minikube](https://minikube.sigs.k8s.io/docs/start/) installed\n* [kubectl](https://kubernetes.io/docs/tasks/tools/) installed\n* [Helm](https://helm.sh/docs/intro/install/) installed\n\n### 1. Helm and Minikube Setup\n\n#### Install Helm and Kubectl\n\n```bash\ndnf install helm kubectl\n```\n\n#### Start Minikube\n\n```bash\nminikube start\n```\n\n#### Confirm Minikube Profile\n\n```bash\nminikube profile list\n```\n\nEnsure the output shows an active profile with status `OK`.\n\n### 2. Verify Helm Functionality\n\n#### Deploy Nginx via Helm\n\n```bash\nhelm install my-release oci://registry-1.docker.io/bitnamicharts/nginx\n```\n\n#### Check Pod Status\n\n```bash\nkubectl get pods\n```\n\nEnsure the Nginx pod shows `STATUS: Running`.\n\n### 3. Enable Persistent Volume Support\n\n#### Enable Required Addons\n\n```bash\nminikube addons enable default-storageclass\nminikube addons enable storage-provisioner\n```\n\n#### Verify Storage Class\n\n```bash\nkubectl get storageclass\n```\n\nEnsure `standard (default)` is listed and uses `k8s.io/minikube-hostpath` as the provisioner.\n\n### 4. Test Nginx Service\n\n#### Port Forward Nginx Service\n\n```bash\nkubectl port-forward svc/my-release-nginx 8080:80\n```\n\nAccess [http://localhost:8080](http://localhost:8080) and confirm the Nginx welcome page is displayed.\n\n![nginx](https://github.com/user-attachments/assets/30de3efc-d5d6-48e2-914e-1aac096b3fa4)\n\n### 5. Clean Up Nginx Deployment\n\n```bash\nhelm uninstall my-release\n```\n\n### 6. Install Jenkins via Helm\n\n#### Add Helm Repo\n\n```bash\nhelm repo add jenkins https://charts.jenkins.io\nhelm repo update\n```\n\n#### Create Namespace and Install Jenkins\n\n```bash\nkubectl create namespace jenkins\nhelm install jenkins jenkins/jenkins -n jenkins\n```\n\n#### Access Jenkins\n\n```bash\nminikube service jenkins -n jenkins\n```\n\nThe Jenkins UI should be accessible on localhost.\n\n![jenking_login](https://github.com/user-attachments/assets/71b2dfef-8e14-45ff-bbe7-1215b196ba67)\n\n#### Get Admin Password\n\n```bash\nkubectl exec --namespace jenkins -it svc/jenkins -c jenkins -- /bin/cat /run/secrets/additional/chart-admin-password\n```\n\n#### Configure Persistent Storage\n\nVerify `jenkins-home` PVC is bound:\n\n```bash\nkubectl get pvc -n jenkins\n```\n\n#### Configure Jenkins Authentication/Security\n\n- Change the default admin password\n- Enable CSRF protection\n- Disable anonymous read access\n\n#### JCasC Configuration\n\nUpgrade Jenkins Helm release with the provided `values.yml` file:\n\n```bash\nhelm upgrade jenkins jenkins/jenkins -n jenkins -f jenkins/values.yml\n```\n\n#### Run a Test Job\n\nCheck the output of the Jenkins job to ensure it completed successfully.\n\n![jenkins_run](https://github.com/user-attachments/assets/696602b4-86c1-4d0e-8362-00e2a9bfc04d)\n\n#### Restart Jenkins Pod\n\nKubernetes will automatically recreate the pod using existing Helm config and PVC.\n\n```bash\nkubectl delete pod -n jenkins -l app.kubernetes.io/component=jenkins-controller\n```\n\nThe pod will restart, and Jenkins will retain its configuration and data.\n\n## Flask App Deployment with Helm on Minikube\n\n### 1. Start Minikube and Configure Docker\n\n```bash\nminikube start\neval $(minikube docker-env)\n```\n\n### 2. Build Docker Image\n\n```bash\ncd app\ndocker build -t flask-app:latest .\n```\n\n### 3. Create Helm Chart\n\nFrom the project root:\n\n```bash\nhelm create flask-app\n```\n\nEdit `values.yaml` in `flask-app/`:\n\n```yaml\nimage:\n  repository: flask-app\n  pullPolicy: IfNotPresent\n  tag: \"latest\"\n\nservice:\n  type: NodePort\n  port: 80\n\ncontainerPort: 5000\n```\n\nIn `flask-app/templates/deployment.yaml`, ensure this line is set:\n\n```yaml\ncontainerPort: {{ .Values.containerPort }}\n```\n\n### 4. Deploy with Helm\n\n```bash\nhelm install flask-app ./flask-app\n```\n\n### 5. Access the App\n\n```bash\nminikube service flask-app\n```\n\nThe browser should open and display `Hello, World!`.\n\n## Cleanup\n\n```bash\nhelm uninstall flask-app\nminikube stop\n```\n\n## CI/CD Pipeline: Flask App on Kubernetes\n\n### **1. Start a Local Docker Registry**\n\n```bash\ndocker run -d -p 5000:5000 --restart=always --name registry registry:2\n```\n\n### **2. Configure Docker to Use Local Registry**\n\nEnsure the Docker image is tagged with the local registry address before pushing:\n\n```bash\ndocker tag flask-app:\u003ctag\u003e localhost:5000/flask-app:\u003ctag\u003e\ndocker push localhost:5000/flask-app:\u003ctag\u003e\n```\n\n### **3. Enable Minikube to Pull from Local Registry**\n\nExpose the local registry inside the Minikube environment. Run:\n\n```bash\nminikube start\n```\n\nThen:\n\n```bash\nminikube ssh -- \"sudo mkdir -p /etc/docker/certs.d/localhost:5000\"\n```\n\nEdit Minikube's Docker daemon configuration to trust the registry (if needed):\n\n```bash\nminikube ssh\necho '{\"insecure-registries\":[\"localhost:5000\"]}' | sudo tee /etc/docker/daemon.json\nsudo systemctl restart docker\nexit\n```\n\n## Monitoring Stack Deployment\n\n### 1. Prometheus\n```sh\nhelm repo add bitnami https://charts.bitnami.com/bitnami\nhelm install prometheus bitnami/kube-prometheus -f helm/prometheus/values.yaml\n```\n\n### 2. Grafana\n```sh\nkubectl apply -f manifests/grafana-secret.yaml\nhelm install grafana bitnami/grafana -f helm/grafana/values.yaml\n```\n\n### 3. Alertmanager Rules\n```sh\nkubectl apply -f alertmanager/alert-rules-configmap.yaml\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fikajdan%2Fdevops-course-tasks","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fikajdan%2Fdevops-course-tasks","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fikajdan%2Fdevops-course-tasks/lists"}