Compare commits

...
15 Commits
Author SHA1 Message Date
Mikhail Lobanov 74908302c0 test: check CI after HTTPS setup
CI / smoke-test (push) Successful in 44s
2026-10-22 21:52:23 +03:00
Mikhail Lobanov 442522cd35 test: check CI after HTTPS setup 2026-10-22 21:52:05 +03:00
Mikhail Lobanov a7e2e6ba0c ci: fix secret name for ssh key
CI / smoke-test (push) Successful in 41s
2026-10-22 21:05:18 +03:00
Mikhail Lobanov fbf2ec7b1a ci: add Ansible deploy step with image_tag; update inventory IP
CI / smoke-test (push) Failing after 20s
2026-10-22 21:00:07 +03:00
Mikhail Lobanov 23421bb70d Ansible deploy Docker
CI / smoke-test (push) Successful in 55s
2026-10-22 17:01:39 +03:00
Mikhail Lobanov d3afe8f908 ci: temporarily disable deployment step
CI / smoke-test (push) Failing after 1m12s
2026-10-21 13:08:44 +03:00
Mikhail Lobanov 74d859b2d7 ci: remove package installation from pipeline
CI / smoke-test (push) Failing after 1s
2026-10-21 12:59:30 +03:00
Mikhail Lobanov 6151e291b9 ci: use local Gitea checkout
CI / smoke-test (push) Failing after 43s
2026-10-21 12:49:18 +03:00
Mikhail Lobanov 7d656c1ae6 ci: deploy application to target via Ansible
CI / smoke-test (push) Failing after 32s
2026-10-21 11:59:49 +03:00
Mikhail Lobanov 5a21852135 Verify health after deployment rollback
CI / smoke-test (push) Successful in 49s
2026-10-15 16:53:32 +03:00
Mikhail Lobanov 027bc8d0bc Verify health after rollback
CI / smoke-test (push) Successful in 46s
2026-10-15 15:47:33 +03:00
Mikhail Lobanov 42bb0db99b Improve Docker Compose rollback
CI / smoke-test (push) Successful in 56s
2026-10-15 12:46:50 +03:00
Mikhail Lobanov 222ae06b87 Add Docker healthcheck
CI / smoke-test (push) Successful in 55s
2026-10-15 00:21:49 +03:00
Mikhail Lobanov 36bd130a28 Use Docker Compose for deployment
CI / smoke-test (push) Successful in 49s
2026-10-14 23:58:02 +03:00
Mikhail Lobanov 4f1c41921d Add Docker Compose configuration 2026-10-14 23:39:19 +03:00
10 changed files with 239 additions and 80 deletions
+14 -80
View File
@@ -13,24 +13,15 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout repository - name: Clone repository from Gitea
uses: actions/checkout@v4 run: |
with: set -eu
github-server-url: http://gitea:3000 git clone http://gitea:3000/Mike/devops-platform.git .
git checkout "${GITHUB_SHA}"
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.12"
- name: Run smoke tests - name: Run smoke tests
run: python3 scripts/smoke_test.py run: python3 scripts/smoke_test.py
- name: Install Docker CLI
run: |
apt-get update
apt-get install -y docker.io
- name: Login to Docker Hub - name: Login to Docker Hub
if: github.event_name == 'push' && github.ref == 'refs/heads/main' if: github.event_name == 'push' && github.ref == 'refs/heads/main'
env: env:
@@ -59,8 +50,9 @@ jobs:
--scanners vuln \ --scanners vuln \
--severity HIGH,CRITICAL \ --severity HIGH,CRITICAL \
--ignore-unfixed \ --ignore-unfixed \
--skip-db-update \
--exit-code 1 \ --exit-code 1 \
mikhaillobanov/devops-platform:${GITHUB_SHA} mikhaillobanov/devops-platform:${GITHUB_SHA}
- name: Push Docker image - name: Push Docker image
if: github.event_name == 'push' && github.ref == 'refs/heads/main' if: github.event_name == 'push' && github.ref == 'refs/heads/main'
@@ -68,71 +60,13 @@ jobs:
docker push mikhaillobanov/devops-platform:latest docker push mikhaillobanov/devops-platform:latest
docker push mikhaillobanov/devops-platform:${GITHUB_SHA} docker push mikhaillobanov/devops-platform:${GITHUB_SHA}
- name: Deploy application - name: Deploy via Ansible
if: github.event_name == 'push' && github.ref == 'refs/heads/main' if: github.event_name == 'push' && github.ref == 'refs/heads/main'
env: env:
IMAGE: mikhaillobanov/devops-platform:${{ github.sha }} ID_RSA: ${{ secrets.ID_RSA }}
run: | run: |
set -eu mkdir -p ~/.ssh
printf '%s\n' "$ID_RSA" | tr -d '\r' > ~/.ssh/id_rsa
OLD_IMAGE=$(docker inspect --format='{{.Image}}' devops-platform) chmod 600 ~/.ssh/id_rsa
ssh -o StrictHostKeyChecking=no -i ~/.ssh/id_rsa root@87.242.118.200 \
docker pull "$IMAGE" "cd /root/devops-platform && ansible-playbook -i ansible/inventory.ini ansible/playbooks/deploy_app.yml -e image_tag=${GITHUB_SHA}"
docker stop devops-platform
docker rm devops-platform
if docker run -d \
--name devops-platform \
--restart unless-stopped \
--read-only \
--cap-drop=ALL \
--security-opt=no-new-privileges:true \
--memory=256m \
--cpus=0.5 \
-p 127.0.0.1:8000:8000 \
"$IMAGE"; then
echo "New container started"
else
echo "Failed to start new container; restoring old image"
docker run -d \
--name devops-platform \
--restart unless-stopped \
--read-only \
--cap-drop=ALL \
--security-opt=no-new-privileges:true \
--memory=256m \
--cpus=0.5 \
-p 127.0.0.1:8000:8000 \
"$OLD_IMAGE"
exit 1
fi
HEALTHY=false
for attempt in $(seq 1 15); do
if docker exec devops-platform python -c \
"import urllib.request; r=urllib.request.urlopen('http://127.0.0.1:8000/health', timeout=2); assert r.status == 200"; then
HEALTHY=true
break
fi
sleep 2
done
if [ "$HEALTHY" = true ]; then
echo "Deployment successful"
else
echo "Health check failed; rolling back"
docker stop devops-platform || true
docker rm devops-platform || true
docker run -d \
--name devops-platform \
--restart unless-stopped \
--read-only \
--cap-drop=ALL \
--security-opt=no-new-privileges:true \
--memory=256m \
--cpus=0.5 \
-p 127.0.0.1:8000:8000 \
"$OLD_IMAGE"
exit 1
fi
+2
View File
@@ -0,0 +1,2 @@
[targets]
ansible-target ansible_host=158.160.223.53 ansible_user=root ansible_ssh_private_key_file=/root/.ssh/id_rsa
+2
View File
@@ -0,0 +1,2 @@
[targets]
ansible-target ansible_host=178.154.209.109 ansible_user=root ansible_ssh_private_key_file=/root/.ssh/id_rsa
@@ -0,0 +1,56 @@
---
- name: Configure Nginx reverse proxy
hosts: targets
become: true
tasks:
- name: Deploy Nginx reverse proxy configuration
ansible.builtin.template:
src: "{{ playbook_dir }}/../templates/devops-platform.conf.j2"
dest: /etc/nginx/sites-available/devops-platform
owner: root
group: root
mode: '0644'
notify: Reload Nginx
- name: Enable DevOps application site
ansible.builtin.file:
src: /etc/nginx/sites-available/devops-platform
dest: /etc/nginx/sites-enabled/devops-platform
state: link
notify: Reload Nginx
- name: Disable default Nginx site
ansible.builtin.file:
path: /etc/nginx/sites-enabled/default
state: absent
notify: Reload Nginx
- name: Validate Nginx configuration
ansible.builtin.command:
cmd: nginx -t
changed_when: false
- name: Apply Nginx changes now
ansible.builtin.meta: flush_handlers
- name: Verify application through Nginx
ansible.builtin.uri:
url: http://127.0.0.1/health
method: GET
status_code: 200
return_content: true
register: proxy_health
retries: 5
delay: 2
until: proxy_health.status == 200
- name: Show proxied application health
ansible.builtin.debug:
var: proxy_health.json
handlers:
- name: Reload Nginx
ansible.builtin.service:
name: nginx
state: reloaded
+56
View File
@@ -0,0 +1,56 @@
---
- name: Deploy DevOps application
hosts: targets
become: true
vars:
deploy_image: "mikhaillobanov/devops-platform:{{ image_tag | default('latest') }}"
tasks:
- name: Create application directory
ansible.builtin.file:
path: /opt/devops-platform
state: directory
owner: root
group: root
mode: '0755'
- name: Copy Docker Compose configuration
ansible.builtin.copy:
src: "{{ playbook_dir }}/../../compose.yaml"
dest: /opt/devops-platform/compose.yaml
owner: root
group: root
mode: '0644'
- name: Deploy application with Docker Compose
ansible.builtin.command:
cmd: docker compose up -d --pull always
chdir: /opt/devops-platform
environment:
IMAGE: "{{ deploy_image }}"
register: deploy_result
changed_when: >
'Created' in deploy_result.stdout or
'Started' in deploy_result.stdout or
'Pulled' in deploy_result.stdout or
'Recreated' in deploy_result.stdout
- name: Wait for application health endpoint
ansible.builtin.uri:
url: http://127.0.0.1:8000/health
method: GET
status_code: 200
return_content: true
register: health_result
retries: 10
delay: 3
until: health_result.status == 200
- name: Show deployed image
ansible.builtin.debug:
msg: "Deployed image: {{ deploy_image }}"
- name: Show application health
ansible.builtin.debug:
var: health_result.json
+28
View File
@@ -0,0 +1,28 @@
---
- name: Install Docker Engine
hosts: targets
become: true
tasks:
- name: Update apt cache
ansible.builtin.apt:
update_cache: true
cache_valid_time: 3600
- name: Install Docker and Compose plugin
ansible.builtin.apt:
name:
- docker.io
- docker-compose-v2
state: present
- name: Ensure Docker is running
ansible.builtin.service:
name: docker
state: started
enabled: true
- name: Verify Docker Compose
ansible.builtin.command:
cmd: docker compose version
changed_when: false
+25
View File
@@ -0,0 +1,25 @@
---
- name: Install and configure Nginx
hosts: targets
become: true
tasks:
- name: Install Nginx
ansible.builtin.apt:
name: nginx
state: present
update_cache: true
- name: Ensure Nginx is running
ansible.builtin.service:
name: nginx
state: started
enabled: true
- name: Deploy index page
ansible.builtin.template:
src: ../templates/index.html.j2
dest: /var/www/html/index.html
owner: root
group: root
mode: '0644'
+16
View File
@@ -0,0 +1,16 @@
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name _;
location / {
proxy_pass http://127.0.0.1:8000;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
+12
View File
@@ -0,0 +1,12 @@
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<title>DevOps Lab</title>
</head>
<body>
<h1>DevOps Lab</h1>
<p>Server: {{ inventory_hostname }}</p>
<p>Managed by Ansible</p>
</body>
</html>
+28
View File
@@ -0,0 +1,28 @@
services:
app:
image: ${IMAGE:-mikhaillobanov/devops-platform:latest}
container_name: devops-platform
restart: unless-stopped
ports:
- "127.0.0.1:8000:8000"
read_only: true
cap_drop:
- ALL
security_opt:
- no-new-privileges:true
mem_limit: 256m
cpus: 0.5
healthcheck:
test:
- CMD
- python
- -c
- "import urllib.request; urllib.request.urlopen('http://127.0.0.1:8000/health', timeout=2)"
interval: 30s
timeout: 3s
retries: 3
start_period: 5s