Skip to content
Open

Lab06 #2874

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
87 changes: 87 additions & 0 deletions .github/workflows/python-ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
name: Python CI (app_python)

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

concurrency:
group: python-ci-${{ github.ref }}
cancel-in-progress: true

jobs:
test-and-lint:
runs-on: ubuntu-latest
defaults:
run:
working-directory: app_python

steps:
- name: Checkout
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
app_python/requirements-dev.txt

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

- name: Lint (ruff)
run: |
ruff check .

- name: Run tests (pytest)
run: |
pytest -q

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

- name: Snyk scan (dependencies)
env:
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
run: snyk test --file=requirements.txt --severity-threshold=high || true


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

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

- name: Generate CalVer version
run: |
echo "VERSION=$(date -u +%Y.%m.%d)-${GITHUB_RUN_NUMBER}" >> $GITHUB_ENV

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

- name: Build and push
uses: docker/build-push-action@v6
with:
context: ./app_python
file: ./app_python/Dockerfile
push: true
tags: |
${{ secrets.DOCKERHUB_USERNAME }}/devops-info-service:${{ env.VERSION }}
${{ secrets.DOCKERHUB_USERNAME }}/devops-info-service:latest
19 changes: 18 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,18 @@
test
test
# Terraform
terraform/.terraform/
terraform/.terraform.lock.hcl
terraform/terraform.tfstate
terraform/terraform.tfstate.backup
terraform/*.tfvars

# Yandex Cloud SA key
.yc/

venv/
*/venv/
__pycache__/
.terraform/
.pulumi/
*.tfstate
*.tfstate.backup
62 changes: 62 additions & 0 deletions ansible/.github/workflows/ansible-deploy.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
name: Ansible Deployment

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

jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.12"
- name: Install ansible + lint
run: pip install ansible ansible-lint
- name: ansible-lint
run: |
cd ansible
ansible-lint playbooks/*.yml

deploy:
needs: lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.12"
- name: Install Ansible + community.docker
run: |
pip install ansible
ansible-galaxy collection install community.docker

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

- name: Create vault pass file
run: |
echo "${{ secrets.ANSIBLE_VAULT_PASSWORD }}" > /tmp/vault_pass
chmod 600 /tmp/vault_pass

- name: Deploy
env:
ANSIBLE_HOST_KEY_CHECKING: "False"
run: |
cd ansible
ansible-playbook playbooks/deploy.yml \
-i inventory/hosts.ini \
--vault-password-file /tmp/vault_pass

- name: Verify
run: |
sleep 5
curl -f "http://${{ secrets.VM_HOST }}:5000/health"
6 changes: 6 additions & 0 deletions ansible/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@

# Ansible
*.retry
.vault_pass
__pycache__/
ansible/.venv/
Empty file added ansible/0
Empty file.
13 changes: 13 additions & 0 deletions ansible/ansible.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
[defaults]
inventory = inventory/hosts.ini
roles_path = roles
host_key_checking = False
remote_user = vboxuser
retry_files_enabled = False
forks = 10
timeout = 30

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

## 1. Architecture Overview

- **Ansible Version:** 2.16+
- **Target OS:** Ubuntu 24.04 LTS
- **Cloud Provider:** Yandex Cloud
- **Application:** DevOps Info Service (FastAPI)
- **Container Runtime:** Docker

This lab implements a fully automated, role-based infrastructure provisioning and container deployment system using Ansible.

### Why Roles?

Roles were used instead of monolithic playbooks to achieve:

- Modularity
- Reusability
- Separation of concerns
- Clean project structure
- Easier scalability and maintenance

---

## 2. Role Structure

### common role
Purpose: Basic system preparation

Tasks:
- Update APT cache
- Install essential packages (curl, git, vim, htop, python3-pip)
- Configure timezone

Idempotency ensured using:
- `apt` module with `state: present`
- `timezone` module

---

### docker role
Purpose: Install and configure Docker

Tasks:
- Install Docker from Ubuntu repository
- Enable and start docker service
- Add user to docker group
- Install python3-docker for Ansible Docker modules

Handlers:
- Restart Docker service (if needed)

All tasks are state-based and idempotent.

---

### web_app role
Purpose: Deploy containerized application securely

Tasks:
- Pull Docker image
- Remove old container if exists
- Run container with restart policy
- Wait for application port
- Perform health check via HTTP

Security:
- Docker Hub credentials stored in encrypted Vault file
- `no_log: true` used for sensitive tasks

---

## 3. Idempotency Demonstration

### First Run

Initial execution resulted in multiple `changed` tasks because packages and services were installed.

### Second Run

Second execution showed:


changed=0


This confirms idempotency.

Idempotency is achieved by:
- Using declarative modules
- Avoiding raw shell commands
- Defining desired system state explicitly

---

## 4. Application Deployment Verification

After deployment:

- Container is running (`docker ps`)
- Port 5000 is exposed publicly
- Health endpoint returns HTTP 200
- Root endpoint returns system metadata

Public URL:

http://93.77.190.119:5000

Health endpoint:

http://93.77.190.119:5000/health

---

## 5. Ansible Vault

Sensitive variables are stored in:


group_vars/all.yml


File is encrypted using:


$ANSIBLE_VAULT;1.1;AES256


Vault ensures:
- Secrets are not stored in plaintext
- Safe version control
- Secure automation

---

## 6. Key DevOps Principles Applied

- Infrastructure as Code
- Idempotent configuration management
- Secure secret management
- Containerized deployment
- Automated verification
- Role-based modular architecture

---

## 7. Conclusion

The system successfully provisions infrastructure, installs Docker, and deploys a containerized application using Ansible roles.

The solution is:

- Idempotent
- Secure
- Modular
- Reproducible
- Production-ready
Loading