Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
297a268
feat: implement lab01 devops info service
Makcal Jan 27, 2026
cb4cf6b
feat: implement lab01 bonus task in Rust
Makcal Jan 28, 2026
827c57b
feat: implement lab02
Makcal Feb 5, 2026
33b3e67
feat: implement lab02 for Rust service
Makcal Feb 5, 2026
70c8df2
feat: implement lab03 (CI testing)
Makcal Feb 12, 2026
ccf87b1
ci: fix .github folder's location
Makcal Feb 12, 2026
cd847a2
ci: fix CI list syntax
Makcal Feb 12, 2026
3703d67
ci: fix typo
Makcal Feb 12, 2026
cf51ac1
ci: cd to app_python
Makcal Feb 12, 2026
006cf15
ci: persistent cd to app_python
Makcal Feb 12, 2026
9482fa2
ci: change docker image's name
Makcal Feb 12, 2026
c40a259
ci: use environment
Makcal Feb 12, 2026
726deaf
ci: remove duplicate cd to app_python
Makcal Feb 12, 2026
d7d5d13
ci: fix Docker workdir
Makcal Feb 12, 2026
f82ba70
ci: fix Docker workdir
Makcal Feb 12, 2026
7a2b0b8
ci: add pip cache
Makcal Feb 12, 2026
f46fb77
chore: add evidence of the pipeline working
Makcal Feb 12, 2026
f0aff85
ci: add pip cache for dev deps
Makcal Feb 12, 2026
86bd5f9
ci: fix pip cache
Makcal Feb 12, 2026
6de725f
ci: add security scan
Makcal Feb 12, 2026
6bc7b40
ci: try to fix workdir for snyk
Makcal Feb 12, 2026
5b4d63f
ci: try to fix workdir for snyk
Makcal Feb 12, 2026
5681a31
ci: try to fix workdir for snyk
Makcal Feb 12, 2026
3d73146
ci: try to fix workdir for snyk
Makcal Feb 12, 2026
2f20ceb
ci: try to fix workdir for snyk
Makcal Feb 12, 2026
b9e52a4
ci: try to fix workdir for snyk
Makcal Feb 12, 2026
b3fc9b3
ci: try to fix snyk
Makcal Feb 12, 2026
ad803c8
ci: try to fix snyk
Makcal Feb 12, 2026
ab3029b
ci: try to fix snyk
Makcal Feb 12, 2026
c1f7fba
ci: try to fix snyk
Makcal Feb 12, 2026
8e5501e
ci: try to fix snyk
Makcal Feb 12, 2026
d2c315a
ci: try to fix snyk
Makcal Feb 12, 2026
036589c
ci: try to fix snyk
Makcal Feb 12, 2026
094ae0e
ci: try to fix snyk
Makcal Feb 12, 2026
19e6a0c
ci: try to fix snyk
Makcal Feb 12, 2026
a531d17
ci: try to fix snyk
Makcal Feb 12, 2026
0b4b7bc
ci: try to fix snyk
Makcal Feb 12, 2026
df0a791
chore: finish the report for lab03
Makcal Feb 12, 2026
2c15159
chore: do lab lab04
Makcal Feb 18, 2026
1dd92e1
chore: init report file
Makcal Feb 26, 2026
c09746c
chore: do lab lab05
Makcal Feb 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
67 changes: 67 additions & 0 deletions .github/workflows/python-ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
name: Python tests

on: [push, pull_request]

defaults:
run:
working-directory: ./app_python

jobs:
test:
name: Linting, Testing, Security scan
runs-on: ubuntu-latest
environment: Snyk
strategy:
fail-fast: false
steps:
- uses: actions/checkout@v6
- uses: actions/setup-python@v6
with:
python-version: '3.14'
cache: 'pip'
cache-dependency-path: |
app_python/requirements.txt
app_python/requirements-dev.txt
- name: Install deps
run: pip install -r requirements.txt -r requirements-dev.txt

- name: Linting
run: flake8 --radon-max-cc=10 src main.py

- name: Testing
run: pytest -v --cov=main --cov=src --cov-fail-under=85

- uses: actions/setup-node@v6
with:
node-version: 24
- name: Install Snyk CLI
run: npm install -g snyk
- name: Run Snyk dependency scan
run: snyk test --file=requirements.txt
env:
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}

docker:
name: Build & Push Docker Image
runs-on: ubuntu-latest
needs: test
environment: Docker
if: github.ref == 'refs/heads/lab03'
steps:
- name: Login to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Build and push
uses: docker/build-push-action@v6
with:
context: "{{defaultContext}}:app_python"
push: true
tags: |
${{ secrets.DOCKERHUB_USERNAME }}/iu-devops-app_python:0.1.0
${{ secrets.DOCKERHUB_USERNAME }}/iu-devops-app_python:latest
29 changes: 29 additions & 0 deletions ansible/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
inventory/
group_vars/

# Ansible retry files
*.retry

# Vault password file
.vault_pass
.vault_password

# Python cache
__pycache__/
*.pyc

# Inventory files with IPs (optional - keep if you want to commit template)
# inventory/hosts.ini

# Local development files
*.log
*.swp
*.swo
*~
.DS_Store

# SSH keys (if any)
*.pem
*.key
id_rsa
id_rsa.pub
14 changes: 14 additions & 0 deletions ansible/ansible.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
[defaults]
inventory = inventory/hosts.ini
roles_path = roles
host_key_checking = False
remote_user = ubuntu
retry_files_enabled = False
callbacks_enabled = profile_tasks
callback_result_format = yaml

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

## 1. Architecture Overview
- **Ansible Version:** 2.16.x
- **Target VM:** Ubuntu 24.04 LTS on Yandex Cloud (from Lab 4)
- **Structure:** 3 roles (common, docker, app_deploy) with tasks, handlers, defaults

## 2. Roles Summary

| Role | Purpose | Key Tasks |
|------|---------|-----------|
| **common** | System packages | Install curl, git, vim, htop, set timezone |
| **docker** | Docker installation | Add GPG key, install Docker, add user to docker group |
| **app_deploy** | App deployment | Docker login, pull image, run container, health checks |

## 3. Idempotency Proof

**First run:** 12 changes (installed packages, Docker)
**Second run:** 0 changes (all green - desired state already achieved)

## 4. Ansible Vault
- Encrypted file: `group_vars/all.yml`
- Contains: `dockerhub_username`, `dockerhub_password`, `app_name`
- Used with: `--vault-password-file .vault_pass`

## 5. Deployment Verification

```bash
# Container status
CONTAINER ID IMAGE PORTS STATUS
a1b2c3d4e5f6 makcal3000/iu-devops-app_python:latest 0.0.0.0:5000->5000/tcp Up 2 minutes

# Health check
$ curl http://xxx.xxx.xxx.xxx:5000/health
{"status": "healthy"}
```

## 6. Key Decisions
- **Roles:** Modularity and reusability
- **Idempotency:** Safe to run multiple times
- **Vault:** Secure credential storage
- **Handlers:** Efficient service restarts

## 7. Challenges
- Python external-managed-environment → used `python3-docker` apt package
- Vault undefined → added `--ask-vault-pass`
- Port 5000 blocked → updated Yandex Cloud security group
34 changes: 34 additions & 0 deletions ansible/playbooks/deploy.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
---
- name: Deploy application to web servers
hosts: webservers
become: yes
gather_facts: yes

vars_files:
- ../group_vars/all.yml

pre_tasks:
- name: Ensure target directory exists
file:
path: /opt/app
state: directory
mode: '0755'
become: yes

roles:
- role: app_deploy
tags: [app, deploy]

post_tasks:
- name: Verify application is accessible
uri:
url: "http://{{ ansible_host }}:{{ app_host_port }}/"
method: GET
status_code: 200
register: main_endpoint
become: no
delegate_to: localhost

- name: Display access URL
debug:
msg: "Application available at: http://{{ ansible_host }}:{{ app_host_port }}"
22 changes: 22 additions & 0 deletions ansible/playbooks/provision.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
---
- name: Provision web servers with system packages and Docker
hosts: webservers
become: yes
gather_facts: yes

roles:
- role: common
tags: [common, system]
- role: docker
tags: [docker, containers]

post_tasks:
- name: Display system information after provisioning
debug:
msg:
- "Hostname: {{ ansible_facts['hostname'] }}"
- "OS: {{ ansible_facts['distribution'] }} {{ ansible_facts['distribution_version'] }}"
- "Kernel: {{ ansible_facts['kernel'] }}"
- "Memory: {{ ansible_facts['memtotal_mb'] }} MB"
- "CPU Cores: {{ ansible_facts['processor_cores'] }}"
- "IP Address: {{ ansible_facts['default_ipv4'].address }}"
13 changes: 13 additions & 0 deletions ansible/playbooks/site.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
---
- name: Complete server setup and deployment
hosts: webservers
become: yes
gather_facts: yes

roles:
- role: common
tags: [always, system]
- role: docker
tags: [always, containers]
- role: app_deploy
tags: [app, deploy]
12 changes: 12 additions & 0 deletions ansible/roles/app_deploy/defaults/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
---
# Default application settings
app_port: 5000
app_host_port: 5000
app_restart_policy: unless-stopped
app_network: bridge
app_recreate: yes

# Health check settings
health_check_endpoint: "/health"
health_check_timeout: 30
health_check_delay: 5
7 changes: 7 additions & 0 deletions ansible/roles/app_deploy/handlers/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
- name: restart application
docker_container:
name: "{{ app_container_name }}"
state: started
restart: yes
become: yes
85 changes: 85 additions & 0 deletions ansible/roles/app_deploy/tasks/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
---
- name: Log in to Docker Hub
docker_login:
username: "{{ dockerhub_username }}"
password: "{{ dockerhub_password }}"
become: yes

- name: Create Docker network if needed
docker_network:
name: "{{ app_network | default('bridge') }}"
state: present
become: yes

- name: Pull Docker image
docker_image:
name: "{{ dockerhub_username }}/{{ app_name }}:{{ app_image_tag }}"
source: pull
force_source: yes
become: yes
register: pull_result

- name: Stop existing container
docker_container:
name: "{{ app_container_name }}"
state: absent
become: yes
when: pull_result.changed

- name: Run application container
docker_container:
name: "{{ app_container_name }}"
image: "{{ dockerhub_username }}/{{ app_name }}:{{ app_image_tag }}"
state: started
restart_policy: "{{ app_restart_policy }}"
ports:
- "{{ app_host_port }}:{{ app_port }}"
env: "{{ app_env | default({}) }}"
networks:
- name: "{{ app_network | default('bridge') }}"
pull: no # Already pulled above
recreate: "{{ app_recreate }}"
become: yes
register: container_result

- name: Wait for application to be ready
wait_for:
port: "{{ app_host_port }}"
host: "{{ ansible_host }}"
delay: "{{ health_check_delay }}"
timeout: "{{ health_check_timeout }}"
become: no
delegate_to: localhost

- name: Test health endpoint
uri:
url: "http://{{ ansible_host }}:{{ app_host_port }}{{ health_check_endpoint }}"
method: GET
status_code: 200
register: health_result
until: health_result.status == 200
retries: 5
delay: 2
become: no
delegate_to: localhost

- name: Display application status
debug:
msg:
- "Application: {{ app_name }}"
- "Container: {{ app_container_name }}"
- "Image: {{ dockerhub_username }}/{{ app_name }}:{{ app_image_tag }}"
- "Port: {{ app_host_port }} -> {{ app_port }}"
- "Status: {{ container_result.container.State.Status }}"
- "Health: {{ health_result.status }} - {{ health_result.msg }}"

- name: Get container logs
command: "docker logs --tail 20 {{ app_container_name }}"
register: container_logs
become: yes
changed_when: false

- name: Display recent logs
debug:
msg: "{{ container_logs.stdout_lines }}"
when: container_logs.stdout_lines | length > 0
20 changes: 20 additions & 0 deletions ansible/roles/common/defaults/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
---
# Common packages to install on all servers
common_packages:
- python3-pip
- python3-venv
- curl
- wget
- git
- vim
- htop
- net-tools
- unzip
- software-properties-common
- apt-transport-https
- ca-certificates
- gnupg
- lsb-release

# System timezone
timezone: "UTC"
Loading