Skip to content

Commit 94f051c

Browse files
authored
Merge pull request #627 from PROCOLLAB-github/prod-release-hardening
Усилен deploy path dev/prod и убран legacy startup flow
2 parents 660ac18 + 2d2c214 commit 94f051c

7 files changed

Lines changed: 141 additions & 54 deletions

File tree

.github/workflows/dev-ci.yml

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ jobs:
5151
5252
docker compose -f docker-compose.dev-ci.yml config >/dev/null
5353
docker compose -f docker-compose.dev-ci.yml build web &&
54+
docker compose -f docker-compose.dev-ci.yml run --rm web python manage.py migrate &&
5455
docker compose -f docker-compose.dev-ci.yml up -d --force-recreate --remove-orphans &&
5556
5657
install -d /etc/nginx/procollab/includes &&
@@ -63,4 +64,47 @@ jobs:
6364
else
6465
sudo nginx -t &&
6566
sudo systemctl reload nginx
66-
fi
67+
fi &&
68+
69+
for attempt in $(seq 1 24); do
70+
root_status="$(curl -s -o /dev/null -w '%{http_code}' https://dev.procollab.ru/ || true)" &&
71+
admin_status="$(curl -s -o /dev/null -w '%{http_code}' https://dev.procollab.ru/admin/login/ || true)" &&
72+
73+
if [ "$root_status" = "401" ] && [ "$admin_status" = "200" ]; then
74+
echo "Smoke check passed on attempt ${attempt}" &&
75+
break
76+
fi
77+
78+
sleep 5
79+
done &&
80+
81+
if [ "$root_status" != "401" ] || [ "$admin_status" != "200" ]; then
82+
echo "Smoke check failed: /=${root_status} /admin/login/=${admin_status}" >&2 &&
83+
exit 1
84+
fi &&
85+
86+
celery_status="" &&
87+
celery_ping="" &&
88+
for attempt in $(seq 1 24); do
89+
celery_status="$(docker inspect -f '{{.State.Status}}' api_celery 2>/dev/null || true)" &&
90+
if [ "$celery_status" = "running" ]; then
91+
celery_ping="$(docker compose -f docker-compose.dev-ci.yml exec -T celerys sh -lc 'celery -A procollab inspect ping -d \"celery@$(hostname)\"' 2>&1 || true)" &&
92+
printf '%s\n' "$celery_ping" &&
93+
if printf '%s\n' "$celery_ping" | grep -q 'pong'; then
94+
echo "Celery check passed on attempt ${attempt}" &&
95+
break
96+
fi
97+
fi &&
98+
99+
sleep 5
100+
done &&
101+
102+
if [ "$celery_status" != "running" ]; then
103+
echo "Celery container is not running: ${celery_status}" >&2 &&
104+
exit 1
105+
fi &&
106+
107+
printf '%s\n' "$celery_ping" | grep -q 'pong' || {
108+
echo "Celery ping failed" >&2
109+
exit 1
110+
}

.github/workflows/release-ci.yml

Lines changed: 77 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,45 @@ on:
1515
type: string
1616

1717
jobs:
18+
prepare:
19+
name: Resolve Release Ref
20+
runs-on: ubuntu-latest
21+
outputs:
22+
image_tag: ${{ steps.vars.outputs.image_tag }}
23+
deploy_ref: ${{ steps.vars.outputs.deploy_ref }}
24+
steps:
25+
- name: Resolve image tag and deploy ref
26+
id: vars
27+
run: |
28+
if [ "${{ github.event_name }}" = "release" ]; then
29+
image_tag='${{ github.event.release.tag_name }}'
30+
deploy_ref='${{ github.event.release.tag_name }}'
31+
else
32+
image_tag='${{ github.event.inputs.image_tag }}'
33+
deploy_ref='${{ github.event.inputs.deploy_ref }}'
34+
fi
35+
36+
if [ -z "$image_tag" ]; then
37+
echo "IMAGE_TAG is empty" >&2
38+
exit 1
39+
fi
40+
41+
if [ -z "$deploy_ref" ]; then
42+
echo "DEPLOY_REF is empty" >&2
43+
exit 1
44+
fi
45+
46+
echo "image_tag=$image_tag" >> "$GITHUB_OUTPUT"
47+
echo "deploy_ref=$deploy_ref" >> "$GITHUB_OUTPUT"
48+
1849
test:
1950
name: Tests
2051
runs-on: ubuntu-latest
52+
needs: [ prepare ]
2153
steps:
2254
- uses: actions/checkout@v3
55+
with:
56+
ref: ${{ needs.prepare.outputs.deploy_ref }}
2357

2458
- name: Set up Python 3.11
2559
uses: actions/setup-python@v4
@@ -57,39 +91,15 @@ jobs:
5791
build:
5892
name: Build Image
5993
runs-on: ubuntu-latest
60-
needs: [ test ]
94+
needs: [ prepare, test ]
6195
outputs:
62-
image_tag: ${{ steps.vars.outputs.image_tag }}
63-
deploy_ref: ${{ steps.vars.outputs.deploy_ref }}
96+
image_tag: ${{ needs.prepare.outputs.image_tag }}
97+
deploy_ref: ${{ needs.prepare.outputs.deploy_ref }}
6498
steps:
6599
- name: "Checkout repository"
66100
uses: actions/checkout@v3
67101
with:
68-
ref: ${{ github.event_name == 'release' && github.event.release.tag_name || github.event.inputs.deploy_ref }}
69-
70-
- name: Resolve image tag
71-
id: vars
72-
run: |
73-
if [ "${{ github.event_name }}" = "release" ]; then
74-
image_tag='${{ github.event.release.tag_name }}'
75-
deploy_ref='${{ github.event.release.tag_name }}'
76-
else
77-
image_tag='${{ github.event.inputs.image_tag }}'
78-
deploy_ref='${{ github.event.inputs.deploy_ref }}'
79-
fi
80-
81-
if [ -z "$image_tag" ]; then
82-
echo "IMAGE_TAG is empty" >&2
83-
exit 1
84-
fi
85-
86-
if [ -z "$deploy_ref" ]; then
87-
echo "DEPLOY_REF is empty" >&2
88-
exit 1
89-
fi
90-
91-
echo "image_tag=$image_tag" >> "$GITHUB_OUTPUT"
92-
echo "deploy_ref=$deploy_ref" >> "$GITHUB_OUTPUT"
102+
ref: ${{ needs.prepare.outputs.deploy_ref }}
93103

94104
- name: "Set up QEMU"
95105
uses: docker/setup-qemu-action@v3
@@ -110,7 +120,7 @@ jobs:
110120
with:
111121
images: ghcr.io/procollab-github/api
112122
tags: |
113-
type=raw,value=${{ steps.vars.outputs.image_tag }}
123+
type=raw,value=${{ needs.prepare.outputs.image_tag }}
114124
- name: Build and push container
115125
uses: docker/build-push-action@v5
116126
with:
@@ -124,7 +134,7 @@ jobs:
124134
deploy:
125135
name: Deploy
126136
runs-on: ubuntu-latest
127-
needs: [ build ]
137+
needs: [ prepare, build ]
128138
steps:
129139
- name: Deploy to server
130140
uses: garygrossgarten/github-action-ssh@release
@@ -135,8 +145,8 @@ jobs:
135145
command: |
136146
set -eu
137147
138-
export IMAGE_TAG="${{ needs.build.outputs.image_tag }}"
139-
export DEPLOY_REF="${{ needs.build.outputs.deploy_ref }}"
148+
export IMAGE_TAG="${{ needs.prepare.outputs.image_tag }}"
149+
export DEPLOY_REF="${{ needs.prepare.outputs.deploy_ref }}"
140150
echo "Deploying IMAGE_TAG=${IMAGE_TAG} from DEPLOY_REF=${DEPLOY_REF}"
141151
142152
if [ "$(id -un)" = "app" ]; then
@@ -150,10 +160,6 @@ jobs:
150160
fi
151161
152162
cd /home/app/procollab-backend
153-
docker container prune -f
154-
docker image prune -a -f
155-
docker compose -f docker-compose.prod-ci.yml -p prod pull
156-
157163
rm -f .env
158164
touch .env
159165
@@ -175,7 +181,9 @@ jobs:
175181
176182
chmod 600 .env
177183
docker compose -f docker-compose.prod-ci.yml -p prod config >/dev/null
184+
docker compose -f docker-compose.prod-ci.yml -p prod pull
178185
186+
docker compose -f docker-compose.prod-ci.yml -p prod run --rm web python manage.py migrate
179187
docker compose -f docker-compose.prod-ci.yml -p prod up -d --remove-orphans
180188
if [ "$(id -u)" -eq 0 ]; then
181189
nginx -t
@@ -186,16 +194,44 @@ jobs:
186194
fi
187195
188196
for attempt in $(seq 1 24); do
189-
root_status="$(curl -k -s -o /dev/null -w '%{http_code}' https://api.procollab.ru/ || true)"
190-
admin_status="$(curl -k -s -o /dev/null -w '%{http_code}' https://api.procollab.ru/admin/login/ || true)"
197+
root_status="$(curl -s -o /dev/null -w '%{http_code}' https://api.procollab.ru/ || true)"
198+
admin_status="$(curl -s -o /dev/null -w '%{http_code}' https://api.procollab.ru/admin/login/ || true)"
191199
192200
if [ "$root_status" = "401" ] && [ "$admin_status" = "200" ]; then
193201
echo "Smoke check passed on attempt ${attempt}"
194-
exit 0
202+
break
203+
fi
204+
205+
sleep 5
206+
done
207+
208+
if [ "$root_status" != "401" ] || [ "$admin_status" != "200" ]; then
209+
echo "Smoke check failed: /=${root_status} /admin/login/=${admin_status}" >&2
210+
exit 1
211+
fi
212+
213+
celery_status=""
214+
celery_ping=""
215+
for attempt in $(seq 1 24); do
216+
celery_status="$(docker inspect -f '{{.State.Status}}' api_celery 2>/dev/null || true)"
217+
if [ "$celery_status" = "running" ]; then
218+
celery_ping="$(docker compose -f docker-compose.prod-ci.yml -p prod exec -T celerys sh -lc 'celery -A procollab inspect ping -d \"celery@$(hostname)\"' 2>&1 || true)"
219+
printf '%s\n' "$celery_ping"
220+
if printf '%s\n' "$celery_ping" | grep -q 'pong'; then
221+
echo "Celery check passed on attempt ${attempt}"
222+
break
223+
fi
195224
fi
196225
197226
sleep 5
198227
done
199228
200-
echo "Smoke check failed: /=${root_status} /admin/login/=${admin_status}"
201-
exit 1
229+
if [ "$celery_status" != "running" ]; then
230+
echo "Celery container is not running: ${celery_status}" >&2
231+
exit 1
232+
fi
233+
234+
printf '%s\n' "$celery_ping" | grep -q 'pong' || {
235+
echo "Celery ping failed" >&2
236+
exit 1
237+
}

Dockerfile

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,5 +27,12 @@ RUN mkdir /procollab/static
2727

2828
COPY . /procollab/
2929

30-
CMD ["bash", "./scripts/startup.sh"]
31-
30+
RUN DJANGO_SECRET_KEY=build-time-secret \
31+
DATABASE_NAME=postgres \
32+
DATABASE_USER=postgres \
33+
DATABASE_PASSWORD=postgres \
34+
DATABASE_HOST=localhost \
35+
DATABASE_PORT=5432 \
36+
python manage.py collectstatic --no-input
37+
38+
CMD ["daphne", "-b", "0.0.0.0", "-p", "8000", "procollab.asgi:application"]

docker-compose.dev-ci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ services:
1717
- "127.0.0.1:8000:8000"
1818

1919
redis:
20-
image: redis:latest
20+
image: redis:7.2.5
2121
restart: unless-stopped
2222
expose:
2323
- 6379

docker-compose.prod-ci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ services:
1313
ports:
1414
- "127.0.0.1:8000:8000"
1515
redis:
16-
image: redis:latest
16+
image: redis:7.2.5
1717
restart: unless-stopped
1818
expose:
1919
- 6379

docker-compose.yml

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,17 @@
1+
# LEGACY compose path.
2+
# Do not use this file for prod or CI/CD deployments.
3+
# Intentional manual use requires: docker compose --profile legacy ...
14
version: '3.9'
25

36
services:
47
web:
8+
profiles: ["legacy"]
59
container_name: web
610
build:
711
context: .
812
dockerfile: ./Dockerfile
913
restart: always
10-
command: bash ./scripts/startup.sh
14+
command: ["daphne", "-b", "0.0.0.0", "-p", "8000", "procollab.asgi:application"]
1115
volumes:
1216
- ./log:/procollab/log
1317
env_file:
@@ -18,6 +22,7 @@ services:
1822
- 8000
1923

2024
nginx:
25+
profiles: ["legacy"]
2126
container_name: nginx
2227
build: ./nginx
2328
depends_on:
@@ -26,6 +31,7 @@ services:
2631
- "8000:80"
2732

2833
redis:
34+
profiles: ["legacy"]
2935
container_name: redis
3036
image: redis:latest
3137
expose:
@@ -34,6 +40,7 @@ services:
3440
- redis-data:/data
3541

3642
celerys:
43+
profiles: ["legacy"]
3744
container_name: api_celery
3845
restart: always
3946
build:

scripts/startup.sh

Lines changed: 0 additions & 7 deletions
This file was deleted.

0 commit comments

Comments
 (0)