Compare commits
15
Commits
68af50b20e
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
74908302c0 | ||
|
|
442522cd35 | ||
|
|
a7e2e6ba0c | ||
|
|
fbf2ec7b1a | ||
|
|
23421bb70d | ||
|
|
d3afe8f908 | ||
|
|
74d859b2d7 | ||
|
|
6151e291b9 | ||
|
|
7d656c1ae6 | ||
|
|
5a21852135 | ||
|
|
027bc8d0bc | ||
|
|
42bb0db99b | ||
|
|
222ae06b87 | ||
|
|
36bd130a28 | ||
|
|
4f1c41921d |
+14
-80
@@ -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
|
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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'
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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>
|
||||||
@@ -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
|
||||||
Reference in New Issue
Block a user