Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
55db2f8
Add solution to first lab
Daniil20xx Jan 28, 2026
5ce9e5f
Add solution to bonus task
Daniil20xx Jan 28, 2026
71a73e7
Add README.md
Daniil20xx Feb 3, 2026
67fd335
Add solution to task2
Daniil20xx Feb 3, 2026
9655d95
Add pytest to test code, tests for pytest and github workflow
Daniil20xx Feb 11, 2026
fdd5a79
Add pytest to test code, tests for pytest and github workflow
Daniil20xx Feb 11, 2026
43adf5f
update .gitignore
Daniil20xx Feb 11, 2026
d8b4b84
update yml
Daniil20xx Feb 11, 2026
c3473ca
Update yml; add first version of md
Daniil20xx Feb 11, 2026
a6bcd6e
Update yml; add first version of md
Daniil20xx Feb 11, 2026
b579d57
Update yml; add first version of md
Daniil20xx Feb 11, 2026
8201c26
Update yml; add first version of md
Daniil20xx Feb 11, 2026
c279429
Update yml; add first version of md
Daniil20xx Feb 11, 2026
68846d0
Update yml; add first version of md
Daniil20xx Feb 11, 2026
8bae40a
Add docker push only in main
Daniil20xx Feb 11, 2026
6f1d0b7
Add snyk test to yml
Daniil20xx Feb 11, 2026
21942db
Add snyk test to yml
Daniil20xx Feb 11, 2026
8a80aa8
bonus task
Daniil20xx Feb 11, 2026
015d3a1
bonus task
Daniil20xx Feb 11, 2026
31936e3
bonus task
Daniil20xx Feb 11, 2026
4254fe4
bonus task
Daniil20xx Feb 11, 2026
882a708
Remove bonus task
Daniil20xx Feb 11, 2026
43b143e
Add terrafrom and bonus task
Daniil20xx Feb 19, 2026
e7b11a4
update yml
Daniil20xx Feb 19, 2026
5de9128
update yml
Daniil20xx Feb 19, 2026
d06f938
update yml
Daniil20xx Feb 19, 2026
a145e61
update yml
Daniil20xx Feb 19, 2026
845b3f7
update yml
Daniil20xx Feb 19, 2026
f730455
update yml
Daniil20xx Feb 19, 2026
089ba6e
update yml
Daniil20xx Feb 19, 2026
0ae6db3
update yml
Daniil20xx Feb 19, 2026
e66cabb
update yml
Daniil20xx Feb 19, 2026
2a08d97
Add solution to lab5
Daniil20xx Feb 25, 2026
670a879
Modify Docker command for SSH folder path
Daniil20xx Feb 25, 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
Binary file added .coverage
Binary file not shown.
83 changes: 83 additions & 0 deletions .github/workflows/python-ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
name: Python CI

on:
push:
paths:
- 'app_python/**'
pull_request:
paths:
- 'app_python/**'

jobs:
test:
runs-on: ubuntu-latest

steps:
- name: Check out code
uses: actions/checkout@v4

- name: Set up Python 3.11
uses: actions/setup-python@v5
with:
python-version: 3.11
cache: "pip"

- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r app_python/requirements.txt
pip install -r app_python/requirements-dev.txt

- name: Run linter
run: ruff check .

- name: Run pytest tests
run: |
pytest -v

- name: Install Snyk CLI
run: npm install -g snyk

- name: Run Snyk Test
env:
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
run: snyk test app_python --severity-threshold=high


terraform-apply:
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main'
needs: test
steps:
- name: Check out code
uses: actions/checkout@v4

- name: Set up Terraform
uses: hashicorp/setup-terraform@v2
with:
terraform_version: 1.14.5

- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v2
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-session-token: ${{ secrets.AWS_SESSION_TOKEN }}
aws-region: us-east-1

- name: Terraform Init
working-directory: app_python/terraform
run: terraform init

- name: Terraform Plan
working-directory: app_python/terraform
run: terraform plan -out=tfplan

- name: Terraform Apply
working-directory: app_python/terraform
env:
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
AWS_SESSION_TOKEN: ${{ secrets.AWS_SESSION_TOKEN }}
AWS_DEFAULT_REGION: us-east-1
run: terraform apply -auto-approve tfplan
15 changes: 14 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,14 @@
test
# Python
__pycache__/
*.py[cod]
venv/
*.log
app_python/venv/
app_python/__pycache__/

# IDE
.vscode/
.idea/

# OS
.DS_Store
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 = maior
retry_files_enabled = False

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

## 1. Architecture Overview

* **Ansible version:** 2.16.14
* **Target VM OS:** Ubuntu 24.04 LTS
* **Role structure:**

```
ansible/
├── inventory/
│ └── hosts.ini # Static inventory
├── roles/
│ ├── common/ # Common system tasks
│ │ ├── tasks/
│ │ │ └── main.yml
│ │ └── defaults/
│ │ └── main.yml
│ ├── docker/ # Docker installation
│ │ ├── tasks/
│ │ │ └── main.yml
│ │ ├── handlers/
│ │ │ └── main.yml
│ │ └── defaults/
│ │ └── main.yml
│ └── app_deploy/ # Application deployment
│ ├── tasks/
│ │ └── main.yml
│ ├── handlers/
│ │ └── main.yml
│ └── defaults/
│ └── main.yml
├── playbooks/
│ ├── site.yml # Main playbook
│ ├── provision.yml # System provisioning
│ └── deploy.yml # App deployment
├── group_vars/
│ └── all.yml # Encrypted variables (Vault)
├── ansible.cfg # Ansible configuration
└── docs/
└── LAB05.md # Your documentation
```

**Why roles?**
Roles allow modular, reusable, and maintainable code. Each role encapsulates tasks, defaults, handlers, and variables, so playbooks remain clean.

# Command to run:
```bash
docker run -it --rm -v ${PWD}\app_python\ansible:/ansible -v my_path_to_ssh_folder\.ssh\vm_machine_ubuntu:/root/.ssh/vm_machine_ubuntu -w /ansible willhallonline/ansible:2.16-debian-bookworm-slim ` bash
```
---

## 2. Roles Documentation

### **2.1 Common Role**

* **Purpose:** Basic system provisioning (apt updates, packages, timezone)
* **Defaults:** `common_packages: [python3-pip, curl, git, vim, htop]`
* **Handlers:** None
* **Dependencies:** None

### **2.2 Docker Role**

* **Purpose:** Install and configure Docker engine
* **Defaults:** Docker version, user to add to `docker` group
* **Handlers:** `restart docker` — restarts Docker service if needed
* **Dependencies:** `common` role

### **2.3 App Deploy Role**

* **Purpose:** Deploy containerized Python app from previous labs
* **Defaults:**
* `app_name: devops-info-service`
* `docker_image_tag: latest`
* `app_port: 5000`
* `app_container_name: devops-info-service`
* link to image: https://hub.docker.com/r/daniil20xx/devops-info-service
* **Handlers:** `restart app container` — restarts app container if task triggers
* **Dependencies:** `docker` role

---

## 3. Idempotency Demonstration

### **3.1 Provisioning (common + docker)**

**First run:**

![playbook-1](/ansible/docs/screenshots/playbook-1.png)

* Tasks with **error** and **changes**

**Second run:**

![playbook-2](/ansible/docs/screenshots/playbook-2.png)


* Tasks with **changes**

**Third run:**

![playbook-3](/ansible/docs/screenshots/playbook-3.png)

* All tasks `ok` (green), `changed=0`
* Idempotency confirmed

### **3.2 Deployment (app_deploy)**

**First run:**

![docker-playbook-1](/ansible/docs/screenshots/docker-playbook-1.png)

* Docker container pulled and started
* `changed=3` (container creation, old container removal, docker login)
* `ignored=1`(container was not created yet)

**Second run:**

![docker-playbook-2](/ansible/docs/screenshots/docker-playhook-2.png)

* Many tasks `ok`, `changed=3`

**Third run:**

![docker-playbook-3](/ansible/docs/screenshots/docker-playhook-3.png)

* Many tasks `ok`, `changed=3`

**Analysis:**

##### changed=3 is repeated why:
- Stop existing container - the module checks if the container is running; even if the container is already running, Ansible marks the task as changed when bringing it to the desired state (e.g. restart or pull latest image).
- Remove old container - the old container is removed (if it is updated or recreated).
- Run container - a new container is created based on the latest image (if tag latest, Ansible pulls the latest image even when restarting).

---

## 4. Ansible Vault Usage

* Vault file: `group_vars/all.yml`

```yaml
dockerhub_username: daniil20xx
dockerhub_password: [HIDDEN]
app_name: devops-info-service
docker_image: "{{ dockerhub_username }}/{{ app_name }}"
docker_image_tag: latest
app_port: 5000
app_container_name: "{{ app_name }}"
```

* Vault password not committed to repo
* Deployed with:

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

* **Purpose:** Keep Docker Hub credentials secure
* **Best practice:** `no_log: true` prevents secrets from appearing in logs

---

## 5. Deployment Verification

**Check containers:**

![docker-check](/ansible/docs/screenshots/docker-check.png)

**Health check:**

![health-check](/ansible/docs/screenshots/working_url.png)

---

## 6. Key Decisions

* **Why use roles instead of plain playbooks?**
Roles separate concerns, making playbooks modular, reusable, and easier to maintain.

* **How do roles improve reusability?**
Each role encapsulates a repeatable task set, which can be reused in multiple projects.

* **What makes a task idempotent?**
Using stateful modules ensures tasks only make changes when necessary.

* **How do handlers improve efficiency?**
Handlers execute only when notified, avoiding unnecessary service restarts.

* **Why is Ansible Vault necessary?**
Vault securely stores credentials and sensitive variables, preventing secrets from leaking in version control.

---

## 7. Challenges

* Run `ansible` on Docker and move nessasary keys to it
* Connect to vm using ansible and ssh keys

---
Binary file added ansible/docs/screenshots/docker-check.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added ansible/docs/screenshots/docker-playbook-1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added ansible/docs/screenshots/docker-playhook-2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added ansible/docs/screenshots/docker-playhook-3.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added ansible/docs/screenshots/playbook-1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added ansible/docs/screenshots/playbook-2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added ansible/docs/screenshots/playbook-3.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added ansible/docs/screenshots/working_url.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
18 changes: 18 additions & 0 deletions ansible/group_vars/all.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
$ANSIBLE_VAULT;1.1;AES256
63343237376635646662623033323332646564316262646434353031376631633166346266656665
6538613565373836363739383566353930383238373262300a316537363039356631653835626238
62323266643836623466646437646532373330656335623064346465633562356334616138366436
3631306637393466350a623161613561326238333131383032373361353861386138636439383736
35633131383032366666663763663730663963373931386465666534343733376365326339623862
66373536353731353838653062636435353462303230393062643735316465646230636136636261
39336265626231623436613266376366353236623634633734643232383731626565636232396538
35323238396364653033623465353938346261636132363365653737636130373732666637636562
37373661616263643239333361393133663133313436366339316362643839653466363731653030
36306234636633383138336334663030636266666434313530336532363637356462383163376538
34363065306237666635326566656662353430616464376266303963666534356232623438366436
37646432333265643239393165643334376663303166336332666530326362623034333030336561
61356563323961633664363338396431373131393062356336386333663133313431353234353231
63376636306231623134613764626139633439353333636665346237343732616434346133636363
35643562376330656563636539336530633039303234626266326330656433653234613937396536
63663863643962353638323739346532656234303234363563326165613866336630633930316137
36383062333939653466643532613134376436653932386262643262396539353837
2 changes: 2 additions & 0 deletions ansible/inventory/hosts.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[webservers]
ubuntu ansible_host=192.168.1.178 ansible_user=maior ansible_ssh_private_key_file=/root/.ssh/vm_machine_ubuntu
7 changes: 7 additions & 0 deletions ansible/playbooks/deploy.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
- name: Deploy application
hosts: webservers
become: yes

roles:
- app_deploy
8 changes: 8 additions & 0 deletions ansible/playbooks/provision.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
- name: Provision web servers
hosts: webservers
become: yes

roles:
- common
- docker
Empty file added ansible/playbooks/site.yml
Empty file.
4 changes: 4 additions & 0 deletions ansible/roles/app_deploy/defaults/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
---
app_port: 5000
app_container_name: devops-info-service
app_restart_policy: unless-stopped
Empty file.
33 changes: 33 additions & 0 deletions ansible/roles/app_deploy/tasks/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
---
- name: Log in to Docker Hub
docker_login:
username: "{{ dockerhub_username }}"
password: "{{ dockerhub_password }}"
no_log: true

- name: Pull application image
docker_image:
name: "{{ docker_image }}"
tag: "{{ docker_image_tag }}"
source: pull

- name: Stop existing container
docker_container:
name: "{{ app_container_name }}"
state: stopped
ignore_errors: yes

- name: Remove old container
docker_container:
name: "{{ app_container_name }}"
state: absent
ignore_errors: yes

- name: Run container
docker_container:
name: "{{ app_container_name }}"
image: "{{ docker_image }}:{{ docker_image_tag }}"
state: started
restart_policy: "{{ app_restart_policy }}"
published_ports:
- "{{ app_port }}:5000"
Loading