Skip to content

Commit 76a0819

Browse files
authored
Merge pull request #29 from GeneralMagicio/develop
carry over CI to main branch
2 parents 817b907 + a89c687 commit 76a0819

File tree

11 files changed

+1206
-665
lines changed

11 files changed

+1206
-665
lines changed
Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
name: prod-pipeline
2+
3+
on:
4+
workflow_dispatch:
5+
push:
6+
branches:
7+
- main
8+
pull_request:
9+
types: [closed]
10+
branches:
11+
- main
12+
13+
jobs:
14+
publish:
15+
runs-on: ubuntu-latest
16+
steps:
17+
- name: Checkout
18+
uses: actions/checkout@v4
19+
- name: Set up QEMU
20+
uses: docker/setup-qemu-action@v3
21+
- name: Set up Docker Buildx
22+
uses: docker/setup-buildx-action@v3
23+
- name: Login to GitHub Container Registry
24+
uses: docker/login-action@v3
25+
with:
26+
registry: ghcr.io
27+
username: ${{ github.actor }}
28+
password: ${{ secrets.GITHUB_TOKEN }}
29+
- name: Build and push
30+
id: build_and_push
31+
uses: docker/build-push-action@v6
32+
with:
33+
context: .
34+
push: true
35+
tags: |
36+
ghcr.io/generalmagicio/worldview-be:main
37+
38+
deploy:
39+
needs: publish
40+
runs-on: ubuntu-latest
41+
steps:
42+
- name: SSH and Redeploy Staging
43+
uses: appleboy/ssh-action@v1.2.0
44+
with:
45+
host: ${{ secrets.PROD_HOST }}
46+
username: ${{ secrets.PROD_USERNAME }}
47+
key: ${{ secrets.PROD_PRIVATE_KEY }}
48+
port: ${{ secrets.SSH_PORT }}
49+
command_timeout: 200m
50+
script: |
51+
set -e
52+
docker system prune -f
53+
# Authenticate with GHCR
54+
echo ${{ secrets.GITHUB_TOKEN }} | docker login ghcr.io -u ${{ github.actor }} --password-stdin
55+
cd worldview-be
56+
git checkout main
57+
git fetch origin main
58+
git reset --hard origin/main
59+
git pull origin main
60+
docker compose pull
61+
62+
rollout-deploy-1:
63+
needs: deploy
64+
runs-on: ubuntu-latest
65+
env:
66+
CONTAINER: "worldview-be1"
67+
steps:
68+
- name: SSH and Redeploy Staging
69+
uses: appleboy/ssh-action@v1.2.0
70+
with:
71+
host: ${{ secrets.PROD_HOST }}
72+
username: ${{ secrets.PROD_USERNAME }}
73+
key: ${{ secrets.PROD_PRIVATE_KEY }}
74+
port: ${{ secrets.SSH_PORT }}
75+
envs: CONTAINER
76+
script: |
77+
## Update each backend service one by one
78+
## First Deployment
79+
export CONTAINER="${CONTAINER}"
80+
cd worldview-be
81+
docker compose rm -fs $CONTAINER
82+
docker compose up --force-recreate -d $CONTAINER
83+
84+
# Wait for $CONTAINER to be healthy (timeout after 5 minutes)
85+
echo "Waiting for $CONTAINER to become healthy..."
86+
if ! timeout 300 bash -c 'until [ "$(docker inspect --format="{{json .State.Health.Status}}" $CONTAINER)" == "\"healthy\"" ]; do echo "Waiting for $CONTAINER to be healthy..."; sleep 5; done'; then
87+
echo "Timeout waiting for $CONTAINER to become healthy"
88+
echo "Container logs:"
89+
docker logs $CONTAINER
90+
exit 1
91+
fi
92+
# Check if $CONTAINER is healthy
93+
if [ "$(docker inspect --format='{{json .State.Health.Status}}' $CONTAINER)" != "\"healthy\"" ]; then
94+
echo "$CONTAINER is not healthy, stopping deployment"
95+
echo "Container logs:"
96+
docker logs $CONTAINER
97+
exit 1
98+
fi
99+
echo "First deployment phase completed successfully"
100+
101+
rollout-deploy-2:
102+
needs: rollout-deploy-1
103+
runs-on: ubuntu-latest
104+
env:
105+
CONTAINER: "worldview-be2"
106+
steps:
107+
- name: SSH and Redeploy Staging
108+
uses: appleboy/ssh-action@v1.2.0
109+
with:
110+
host: ${{ secrets.PROD_HOST }}
111+
username: ${{ secrets.PROD_USERNAME }}
112+
key: ${{ secrets.PROD_PRIVATE_KEY }}
113+
port: ${{ secrets.SSH_PORT }}
114+
envs: CONTAINER
115+
script: |
116+
## Update each backend service one by one
117+
## Second Deployment
118+
export CONTAINER="${CONTAINER}"
119+
cd worldview-be
120+
docker compose rm -fs $CONTAINER
121+
docker compose up --force-recreate -d $CONTAINER
122+
123+
# Wait for $CONTAINER to be healthy (timeout after 5 minutes)
124+
echo "Waiting for $CONTAINER to become healthy..."
125+
if ! timeout 300 bash -c 'until [ "$(docker inspect --format="{{json .State.Health.Status}}" $CONTAINER)" == "\"healthy\"" ]; do echo "Waiting for $CONTAINER to be healthy..."; sleep 5; done'; then
126+
echo "Timeout waiting for $CONTAINER to become healthy"
127+
echo "Container logs:"
128+
docker logs $CONTAINER
129+
exit 1
130+
fi
131+
# Check if $CONTAINER is healthy
132+
if [ "$(docker inspect --format='{{json .State.Health.Status}}' $CONTAINER)" != "\"healthy\"" ]; then
133+
echo "$CONTAINER is not healthy, stopping deployment"
134+
echo "Container logs:"
135+
docker logs $CONTAINER
136+
exit 1
137+
fi
138+
echo "Second deployment phase completed successfully"
Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
name: staging-pipeline
2+
3+
on:
4+
workflow_dispatch:
5+
push:
6+
branches:
7+
- develop
8+
pull_request:
9+
types: [closed]
10+
branches:
11+
- develop
12+
13+
jobs:
14+
publish:
15+
runs-on: ubuntu-latest
16+
steps:
17+
- name: Checkout
18+
uses: actions/checkout@v4
19+
- name: Set up QEMU
20+
uses: docker/setup-qemu-action@v3
21+
- name: Set up Docker Buildx
22+
uses: docker/setup-buildx-action@v3
23+
- name: Login to GitHub Container Registry
24+
uses: docker/login-action@v3
25+
with:
26+
registry: ghcr.io
27+
username: ${{ github.actor }}
28+
password: ${{ secrets.GITHUB_TOKEN }}
29+
- name: Build and push
30+
id: build_and_push
31+
uses: docker/build-push-action@v6
32+
with:
33+
context: .
34+
push: true
35+
tags: |
36+
ghcr.io/generalmagicio/worldview-be:staging
37+
38+
deploy:
39+
needs: publish
40+
runs-on: ubuntu-latest
41+
steps:
42+
- name: SSH and Redeploy Staging
43+
uses: appleboy/ssh-action@v1.2.0
44+
with:
45+
host: ${{ secrets.STAGING_HOST }}
46+
username: ${{ secrets.STAGING_USERNAME }}
47+
key: ${{ secrets.STAGING_PRIVATE_KEY }}
48+
port: ${{ secrets.SSH_PORT }}
49+
command_timeout: 200m
50+
script: |
51+
set -e
52+
docker system prune -f
53+
# Authenticate with GHCR
54+
echo ${{ secrets.GITHUB_TOKEN }} | docker login ghcr.io -u ${{ github.actor }} --password-stdin
55+
cd worldview-be
56+
git checkout develop
57+
git fetch origin develop
58+
git reset --hard origin/develop
59+
git pull origin develop
60+
docker compose pull
61+
62+
rollout-deploy-1:
63+
needs: deploy
64+
runs-on: ubuntu-latest
65+
env:
66+
CONTAINER: 'worldview-be1'
67+
steps:
68+
- name: SSH and Redeploy Staging
69+
uses: appleboy/ssh-action@v1.2.0
70+
with:
71+
host: ${{ secrets.STAGING_HOST }}
72+
username: ${{ secrets.STAGING_USERNAME }}
73+
key: ${{ secrets.STAGING_PRIVATE_KEY }}
74+
port: ${{ secrets.SSH_PORT }}
75+
envs: CONTAINER
76+
script: |
77+
## Update each backend service one by one
78+
## First Deployment
79+
export CONTAINER="${CONTAINER}"
80+
cd worldview-be
81+
docker compose rm -fs $CONTAINER
82+
docker compose up --force-recreate -d $CONTAINER
83+
84+
# Wait for $CONTAINER to be healthy (timeout after 5 minutes)
85+
echo "Waiting for $CONTAINER to become healthy..."
86+
if ! timeout 300 bash -c 'until [ "$(docker inspect --format="{{json .State.Health.Status}}" $CONTAINER)" == "\"healthy\"" ]; do echo "Waiting for $CONTAINER to be healthy..."; sleep 5; done'; then
87+
echo "Timeout waiting for $CONTAINER to become healthy"
88+
echo "Container logs:"
89+
docker logs $CONTAINER
90+
exit 1
91+
fi
92+
# Check if $CONTAINER is healthy
93+
if [ "$(docker inspect --format='{{json .State.Health.Status}}' $CONTAINER)" != "\"healthy\"" ]; then
94+
echo "$CONTAINER is not healthy, stopping deployment"
95+
echo "Container logs:"
96+
docker logs $CONTAINER
97+
exit 1
98+
fi
99+
echo "First deployment phase completed successfully"
100+
101+
rollout-deploy-2:
102+
needs: rollout-deploy-1
103+
runs-on: ubuntu-latest
104+
env:
105+
CONTAINER: 'worldview-be2'
106+
steps:
107+
- name: SSH and Redeploy Staging
108+
uses: appleboy/ssh-action@v1.2.0
109+
with:
110+
host: ${{ secrets.STAGING_HOST }}
111+
username: ${{ secrets.STAGING_USERNAME }}
112+
key: ${{ secrets.STAGING_PRIVATE_KEY }}
113+
port: ${{ secrets.SSH_PORT }}
114+
envs: CONTAINER
115+
script: |
116+
## Update each backend service one by one
117+
## Second Deployment
118+
export CONTAINER="${CONTAINER}"
119+
cd worldview-be
120+
docker compose rm -fs $CONTAINER
121+
docker compose up --force-recreate -d $CONTAINER
122+
123+
# Wait for $CONTAINER to be healthy (timeout after 5 minutes)
124+
echo "Waiting for $CONTAINER to become healthy..."
125+
if ! timeout 300 bash -c 'until [ "$(docker inspect --format="{{json .State.Health.Status}}" $CONTAINER)" == "\"healthy\"" ]; do echo "Waiting for $CONTAINER to be healthy..."; sleep 5; done'; then
126+
echo "Timeout waiting for $CONTAINER to become healthy"
127+
echo "Container logs:"
128+
docker logs $CONTAINER
129+
exit 1
130+
fi
131+
# Check if $CONTAINER is healthy
132+
if [ "$(docker inspect --format='{{json .State.Health.Status}}' $CONTAINER)" != "\"healthy\"" ]; then
133+
echo "$CONTAINER is not healthy, stopping deployment"
134+
echo "Container logs:"
135+
docker logs $CONTAINER
136+
exit 1
137+
fi
138+
echo "Second deployment phase completed successfully"

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ lerna-debug.log*
3636
!.vscode/extensions.json
3737

3838
# dotenv environment variable files
39-
.env
39+
.env*
4040
.env.development.local
4141
.env.test.local
4242
.env.production.local
@@ -54,3 +54,4 @@ pids
5454

5555
# Diagnostic reports (https://nodejs.org/api/report.html)
5656
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
57+
.yarn

.yarnrc.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
nodeLinker: node-modules

Caddyfile

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
{$BACKEND_URL} {
2+
route {
3+
@allowed {
4+
path /*
5+
remote_ip {$IP_WHITELIST}
6+
}
7+
reverse_proxy @allowed {
8+
to worldview-be1:3000 worldview-be2:3000
9+
lb_policy round_robin
10+
health_uri /
11+
health_interval 5s
12+
health_timeout 2s
13+
health_status 200
14+
}
15+
respond 403
16+
}
17+
}

Dockerfile

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
FROM node:22-alpine
2+
3+
WORKDIR /usr/src/app
4+
COPY package*.json ./
5+
COPY tsconfig*.json ./
6+
COPY yarn.lock ./
7+
RUN apk update
8+
RUN apk add --no-cache curl openssl
9+
RUN npm install -g @nestjs/cli
10+
RUN npm install -g corepack && corepack enable
11+
RUN yarn install
12+
COPY . .
13+
RUN yarn prisma generate
14+
RUN yarn run build
15+
EXPOSE 3000
16+
ENTRYPOINT ["sh", "-c", "npx prisma migrate deploy && yarn run start:prod"]

docker-compose-local.yml

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
services:
2+
worldview-be:
3+
build:
4+
context: .
5+
container_name: worldview-be
6+
restart: always
7+
env_file:
8+
- .env
9+
ports:
10+
- 3000
11+
networks:
12+
- worldview-backend
13+
depends_on:
14+
worldview-db:
15+
condition: service_healthy
16+
postgres:
17+
image: postgres:16
18+
container_name: postgres_db
19+
restart: always
20+
environment:
21+
- POSTGRES_DB=qv
22+
- POSTGRES_USER=postgres
23+
- POSTGRES_PASSWORD=postgres
24+
volumes:
25+
- postgres_data:/var/lib/postgresql/data
26+
networks:
27+
- worldview-backend
28+
ports:
29+
- '5433:5432'
30+
healthcheck:
31+
test: ["CMD", "pg_isready", "-U", "postgres", "-d", "qv"]
32+
interval: 10s
33+
timeout: 5s
34+
retries: 5
35+
36+
volumes:
37+
postgres_data:
38+
driver: local
39+
40+
networks:
41+
worldview-backend:
42+
driver: bridge

0 commit comments

Comments
 (0)