Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
79 changes: 79 additions & 0 deletions .github/workflows/ansible-deploy.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
name: Ansible Deployment

on:
push:
branches: [main, master, lab06]
paths:
- "ansible/**"
- ".github/workflows/ansible-deploy.yml"
pull_request:
branches: [main, master, lab06]
paths:
- "ansible/**"

jobs:
lint:
name: Ansible Lint
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 dependencies
run: |
pip install ansible ansible-lint

- name: Run ansible-lint
env:
ANSIBLE_VAULT_PASSWORD: ${{ secrets.ANSIBLE_VAULT_PASSWORD }}
run: |
cd ansible
echo "$ANSIBLE_VAULT_PASSWORD" > /tmp/vault_pass
export ANSIBLE_VAULT_PASSWORD_FILE=/tmp/vault_pass
ansible-lint playbooks/*.yml
rm /tmp/vault_pass

deploy:
name: Deploy Application
needs: lint
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
run: pip install ansible

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

- name: Deploy with Ansible
env:
ANSIBLE_VAULT_PASSWORD: ${{ secrets.ANSIBLE_VAULT_PASSWORD }}
ANSIBLE_HOST_KEY_CHECKING: False
run: |
cd ansible
echo "$ANSIBLE_VAULT_PASSWORD" > /tmp/vault_pass
ansible-playbook playbooks/deploy.yml \
-i inventory/hosts.ini \
--vault-password-file /tmp/vault_pass
rm /tmp/vault_pass

- name: Verify Deployment
run: |
sleep 10
curl -f http://${{ secrets.VM_HOST }}:5000 || exit 1
curl -f http://${{ secrets.VM_HOST }}:5000/health || exit 1
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 CI

on:
push:
paths:
- "app_python/**"
- ".github/workflows/python-ci.yml"
pull_request:
paths:
- "app_python/**"

jobs:
test-and-build:
runs-on: ubuntu-latest

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

- name: Cache pip dependencies
uses: actions/cache@v3
with:
path: ~/.cache/pip
key: ${{ runner.os }}-pip-${{ hashFiles('app_python/requirements.txt') }}
restore-keys: |
${{ runner.os }}-pip-

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

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

- name: Run tests
run: |
cd app_python
pytest

- name: Docker login
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}

- name: Set Docker image version
run: echo "VERSION=$(date +%Y.%m.%d)" >> $GITHUB_ENV

- name: Build and push Docker image
uses: docker/build-push-action@v6
with:
context: app_python
push: true
tags: |
${{ secrets.DOCKERHUB_USERNAME }}/devops-info-python:${{ env.VERSION }}
${{ secrets.DOCKERHUB_USERNAME }}/devops-info-python:latest

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

- name: Run Snyk test
env:
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
run: snyk test --all-projects --severity-threshold=high
10 changes: 10 additions & 0 deletions ansible/ansible.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[defaults]
inventory = inventory/hosts.ini
host_key_checking = False
remote_user = ubuntu
retry_files_enabled = False

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

## 1. Architecture Overview
- Ansible version: 2.15+ (tested on macOS with Python 3.10)

- Target VM OS: Ubuntu 22.04 LTS (5.15.0-151-generic)

- Role structure:
```
roles/
├── common
│ ├── tasks/
│ │ └── main.yml
│ └── defaults/
│ └── main.yml
├── docker
│ ├── tasks/
│ │ └── main.yml
│ ├── handlers/
│ │ └── main.yml
│ └── defaults/
│ └── main.yml
└── app_deploy
├── tasks/
│ └── main.yml
├── handlers/
│ └── main.yml
└── defaults/
└── main.yml
```

- Why roles: Roles separate concerns (system provisioning, Docker setup, app deployment), making playbooks modular, reusable, and easier to maintain.

## 2. Roles Documentation
**common**
- **Purpose**: Update system, install essential packages, optionally set timezone.
- **Variables**:
- `common_packages` — list of packages (`python3-pip, curl, git, vim, htop`),
- `timezone` — default: `UTC`
- **Handlers**: None
- **Dependencies**: None

**docker**
- **Purpose**: Install Docker, configure repository, ensure Docker service running, manage user access.
- **Variables**:
- `docker_version` — optional version constraints,
- `docker_user` — user to add to docker group
- **Handlers**: `restart docker` — triggered when Docker config changes
- **Dependencies**: `common` role should run first

**app_deploy**
- **Purpose**: Pull and run containerized Python app securely using Vault credentials.
- **Variables**:
- `dockerhub_username`, `dockerhub_password` (vaulted);
- `app_name`, `docker_image_tag`, `app_port`, `app_container_name`
- **Handlers**:
- `restart application container` — restarts container if configuration changes
- **Dependencies**: Depends on `docker` role

## 3. Idempotency Demonstration
**First run of** `provision.yml`:

![first run](screenshots/first%20run.png)

**Second run**:

![first run](screenshots/second%20run.png)

**Analysis**:
- First run: packages installed, Docker configured, user added — all tasks changed state.
- Second run: nothing changed because tasks checked current state before applying changes.
- **Idempotency**: Roles and tasks are designed to only make changes if the target state differs from the actual state.

## 4. Ansible Vault Usage
- **Secure storage**: Docker Hub credentials stored in `group_vars/all.yml` encrypted via `ansible-vault`.
- **Vault password strategy**: Use `--ask-vault-pass` or password file (not committed to repo).
- **Importance**: Protects sensitive credentials from accidental exposure in version control.

## 5. Deployment Verification

**Playbook run**:
![playbook run](screenshots/deployment%20playbook.png)

**Container status**:
![container status](screenshots/docker%20ps.png)

**Health check**:
![main endpoint](screenshots/main%20endpoint.png)
![health check](screenshots/health%20check.png)

**Handler execution**: The restart handler triggered only when container needed restart.

## 6. Key Decisions

- **Why roles**: Keep playbooks modular, easier to maintain, and reusable.
- **Reusability**: Roles can be applied to multiple hosts or projects without duplicating logic.
- **Idempotent tasks**: Ensure they check state before applying changes (apt, docker, etc.).
- **Handlers efficiency**: Avoid unnecessary restarts; only run when a change occurs.
- **Vault necessity**: Keeps sensitive credentials secure, prevents leaks in source control.

## 7. Challenges
- Docker Hub login failing when vault not loaded → resolved by including `vars_files` in playbook.
- Container inaccessible from outside → fixed by restarting.
- Handlers misconfigured (`state: restarted` not valid) → corrected to `started`.
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/lab5/screenshots/docker ps.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/lab5/screenshots/first run.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/lab5/screenshots/health 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/lab5/screenshots/main endpoint.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/lab5/screenshots/second run.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading