Skip to content
Open

Lab09 #3269

Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
dd52d92
feat: implement lab01 devops info service
flowelx Jan 26, 2026
b762288
feat: implement lab01 devops info service
flowelx Jan 28, 2026
05640b0
feat: implement lab01 devops info service
flowelx Jan 28, 2026
73b69d5
feat: implement lab01 devops info service
flowelx Jan 28, 2026
5dff649
feat: implement lab01 devops info service
flowelx Jan 28, 2026
da6f2be
feat: implement lab01 devops info service
flowelx Jan 28, 2026
dcfb223
feat: implement lab01 devops info service
flowelx Jan 28, 2026
77b3071
feat: implement lab01 devops info service
flowelx Jan 28, 2026
7f8c962
feat: implement java lab01 devops info service
flowelx Jan 28, 2026
e9fc8d1
Merge branch 'lab01' of github.com:flowelx/DevOps-Core-Course into lab01
flowelx Jan 28, 2026
e9287f9
docs: add PR template
flowelx Jan 28, 2026
c4479c6
Merge pull request #1 from flowelx/lab01
flowelx Feb 4, 2026
ffc718e
feat: containerize FastAPI app with Docker
flowelx Feb 4, 2026
bbdedb8
feat: containerize FastAPI app with Docker
flowelx Feb 5, 2026
f6579ad
Merge pull request #2 from flowelx/lab02
flowelx Feb 7, 2026
f28b276
feat: add pytest and ci
flowelx Feb 7, 2026
1202d24
feat: add ci
flowelx Feb 7, 2026
93d863e
feat: add status badge and complete ci
flowelx Feb 7, 2026
71444e8
docs: add documentation for lab03
flowelx Feb 7, 2026
44c49ea
docs: add status badge screenshot
flowelx Feb 7, 2026
91fdcf4
Merge branch 'inno-devops-labs:master' into master
flowelx Feb 18, 2026
aebfad0
Merge pull request #3 from flowelx/lab03
flowelx Feb 18, 2026
b746823
complete lab04
flowelx Feb 19, 2026
6cb3129
Merge branch 'inno-devops-labs:master' into master
flowelx Feb 26, 2026
edacfbd
Merge pull request #4 from flowelx/lab04
flowelx Feb 26, 2026
7419f04
complete lab05
flowelx Feb 26, 2026
56e834d
Merge pull request #5 from flowelx/lab05
flowelx Mar 5, 2026
a55a05b
complete lab06
flowelx Mar 5, 2026
bc3eaab
fix ci/cd
flowelx Mar 5, 2026
0885917
add report
flowelx Mar 5, 2026
8fb986a
Merge pull request #6 from flowelx/lab06
flowelx Mar 12, 2026
5d4e126
complete lab
flowelx Mar 12, 2026
b73dc12
Merge pull request #7 from flowelx/lab07
flowelx Mar 19, 2026
6f4c92d
complete lab
flowelx Mar 20, 2026
1b4d8be
Merge branch 'inno-devops-labs:master' into master
flowelx Mar 26, 2026
4780d98
Merge pull request #8 from flowelx/lab08
flowelx Mar 26, 2026
5e1feb1
complete lab
flowelx Mar 26, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
91 changes: 91 additions & 0 deletions .github/workflows/ansible-deploy.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
name: Ansible Deployment

on:
push:
branches: [ main ]
paths:
- 'ansible/**'
- '.github/workflows/ansible-deploy.yml'
pull_request:
branches: [ main ]
paths:
- 'ansible/**'

jobs:
lint:
name: Lint Ansible Code
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.12'

- name: Install ansible-lint
run: pip install ansible-lint

- name: Run ansible-lint
run: |
cd ansible
ansible-lint playbooks/deploy.yml

deploy:
name: Deploy Application
needs: lint
runs-on: ubuntu-latest
if: github.event_name == 'push'

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.12'

- name: Install Ansible
run: pip install ansible

- name: Setup SSH
run: |
mkdir -p ~/.ssh
echo "${{ secrets.SSH_PRIVATE_KEY }}" > ~/.ssh/id_rsa
chmod 600 ~/.ssh/id_rsa
ssh-keyscan -H ${{ secrets.VM_HOST }} >> ~/.ssh/known_hosts

- name: Create inventory
run: |
mkdir -p ansible/inventory
echo "[webservers]" > ansible/inventory/hosts.ini
echo "${{ secrets.VM_HOST }} ansible_user=${{ secrets.VM_USER }}" >> ansible/inventory/hosts.ini

- name: Decrypt vault password
run: echo "${{ secrets.ANSIBLE_VAULT_PASSWORD }}" > /tmp/vault_pass

- name: Run Ansible playbook
run: |
cd ansible
ansible-playbook playbooks/deploy.yml \
-i inventory/hosts.ini \
--vault-password-file /tmp/vault_pass

- name: Cleanup
if: always()
run: rm -f /tmp/vault_pass

verify:
name: Verify Deployment
needs: deploy
runs-on: ubuntu-latest
if: success()

steps:
- name: Check application
run: |
sleep 10
curl -f http://${{ secrets.VM_HOST }}:8000/health || exit 1
echo "Application verified successfully"
73 changes: 73 additions & 0 deletions .github/workflows/python-ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
name: Python CI/CD

on:
push:
branches: [ main, lab03 ]
paths:
- 'app_python/**'
- '.github/workflows/python-ci.yml'
pull_request:
branches: [ main ]
paths:
- 'app_python/**'
- '.github/workflows/python-ci.yml'

jobs:
test:
runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.12'
cache: 'pip'
cache-dependency-path: 'app_python/requirements.txt'

- name: Install dependencies
run: |
cd app_python
pip install -r requirements.txt

- name: Run linter
run: |
cd app_python
flake8 app.py

- name: Run tests
run: |
cd app_python
pytest tests/test_app.py

- name: Security scan with pip-audit
run: |
cd app_python
pip install pip-audit
pip-audit -r requirements.txt || echo "Security scan completed"

build:
runs-on: ubuntu-latest
needs: test
if: github.event_name == 'push' && github.ref == 'refs/heads/main'

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Login to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_TOKEN }}

- name: Build and push Docker image
uses: docker/build-push-action@v5
with:
context: ./app_python
push: true
tags: |
${{ secrets.DOCKER_USERNAME }}/fastapi-lab-app:latest
${{ secrets.DOCKER_USERNAME }}/fastapi-lab-app:$(date +%Y.%m.%d)
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
test
test
all.yml
.env
11 changes: 11 additions & 0 deletions ansible/ansible.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
[defaults]
inventory = inventory/hosts.ini
roles_path = roles
host_key_checking = False
remote_user = ubuntu
retry_files_enabled = False

[privilege_escalation]
become = True
become_method = sudo
become_user = root
147 changes: 147 additions & 0 deletions ansible/docs/LAB05.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
# Lab 5 — Ansible Fundamentals

## 1. Architecture Overview

### Ansible version used

```bash
ansible --version
ansible [core 2.20.1]
```

### Target VM OS and version

**Ubuntu 22.04 LTS**

### Role structure explanation

1. `common` role configures base system for server
2. `docker` role installs and configures Docker
3. `app_deploy` role deploys the actual application

`common` role -> `docker` role -> `app_deploy` role

### Why roles instead of monolithic playbooks?

Using roles instead of monolithic playbooks ensures better readability as this provides clear separation of concerns and it's easier to debug and update isolated components.

## 2. Roles Documentation

### `common` role:

**Purpose:** Configures base system for server
**Variables:** Common packages and timezone
**Handlers:** No handlers
**Dependencies:** No dependencies

### `docker` role:

**Purpose:** Installs and configures Docker
**Variables:** Dokcer version, Docker Compose version, Docker users, Docker repository URL, Docker GPG key URL
**Handlers:** Docker restart
**Dependencies:** Depends on `common` role

### `deploy` role:

**Purpose:** Deploys the actual application
**Variables:** Application settings, Docker settings, environment variables, health check and vault variables
**Handlers:** App container restart and reload
**Dependencies:** Depends on `docker` role

## 3. Idempotency Demonstration

### Terminal output from FIRST provision.yml run

![](screenshots/first-provision.jpg)

### Terminal output from SECOND provision.yml run

![](screenshots/second-provision.jpg)

### Analysis: What changed first time? What didn't change second time?

Most of the tasks were changed first time. Packets, Docker, container weren't on the server. Then second time only 1 task was changed because I set `cache_valid_time: 3600` for cache update. Ansible checks system state and doesn't do unnecessary actions. If everything is set properly, nothing changes.

### Explanation: What makes your roles idempotent?

I used `state: present' that ensures packages are intalled.

## 4. Ansible Vault Usage

### How you store credentials securely

I use **Ansible Vault** to encrypt sensitive data.

### Vault password management strategy

```bash
ansible-playbook playbooks/deploy.yml --ask-vault-pass
```

### Example of encrypted file (show it's encrypted!)

![](screenshots/encrypted-data.jpg)

### Why Ansible Vault is important

Ansible Vault is important because passwords are encrypted and it's safe in case of pushing file to git.

## 5. Deployment Verification

### Terminal output from deploy.yml run

![](screenshots/deploy.jpg)

### Container status: docker ps output

![](screenshots/docker-ps.jpg)

### Health check verification: curl outputs

```bash
curl http://62.84.120.249:5000/health | jq
{
"status": "healthy",
"timestamp": "2026-02-26T20:42:46.002Z",
"uptime_seconds": 10337
}
```

## 6. Key Decisions

### Why use roles instead of plain playbooks?

- **Organization** - Roles group related tasks, variables, and handlers together
- **Readability** - Playbooks become clean and simple (just list roles)
- **Reusability** - Same role can be used in multiple playbooks
- **Maintainability** - Easier to update and debug isolated components

### How do roles improve reusability?

- **Parameterization** - Variables make roles adaptable to different environments
- **Encapsulation** - All dependencies are contained within the role
- **Sharing** - Roles can be shared via Ansible Galaxy
- **Composability** - Mix and match roles for different server types

### What makes a task idempotent?

- **State checking** - Modules check current state before making changes
- **Declarative syntax** - Describe the desired state, not how to achieve it
- **Conditionals** - Tasks run only when needed (e.g., when: container_info.exists)
- **No "latest"** - Using state: present instead of state: latest
- **Idempotent modules** - Ansible modules are designed to be idempotent

### How do handlers improve efficiency?

- **Run-once** - Execute only once, even if notified by multiple tasks
- **Conditional execution** - Run only when changes actually occur
- **Order control** - Execute at the end of the play, not during
- **Resource savings** - Prevent unnecessary restarts (e.g., restart Docker once, not multiple times)

### Why is Ansible Vault necessary?

- **Security** - Encrypts sensitive data (passwords, tokens, keys)
- **Version control safe** - Can commit encrypted files to git
- **Compliance** - Meets security standards and audit requirements
- **Team collaboration** - Share code without sharing secrets
- **Multi-environment** - Different passwords for dev/staging/production
Loading