Skip to content
This repository was archived by the owner on Aug 27, 2025. It is now read-only.

Commit 596cb2d

Browse files
authored
Merge pull request #9 from Crossbell-Box/feat-deploy
feat: deploy
2 parents 0cc4d8d + 022f7ab commit 596cb2d

11 files changed

Lines changed: 344 additions & 0 deletions

File tree

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
name: Docker Build
2+
3+
on:
4+
push:
5+
branches:
6+
- "main"
7+
tags:
8+
- "v*.*.*"
9+
10+
env:
11+
IMAGE_NAME: rss3/xchar
12+
REGION_ID: us-east-1
13+
DEV_ACK_CLUSTER_ID: cd1d0ffc40b5242b39ddda1864e71e30d
14+
PROD_ACK_CLUSTER_ID: cfc647c22fd6848b5a602ad4d7470632b
15+
16+
jobs:
17+
build:
18+
runs-on: ubuntu-latest
19+
outputs:
20+
version: ${{ steps.meta.outputs.version }}
21+
steps:
22+
- name: Checkout
23+
uses: actions/checkout@v2
24+
- name: docker meta
25+
id: meta
26+
uses: docker/metadata-action@v3
27+
with:
28+
images: ${{ env.IMAGE_NAME }}
29+
tags: |
30+
type=sha
31+
- name: Set up Docker Buildx
32+
uses: docker/setup-buildx-action@v1
33+
- name: Login to DockerHub
34+
if: github.event_name != 'pull_request'
35+
uses: docker/login-action@v1
36+
with:
37+
username: ${{ secrets.DOCKERHUB_USERNAME }}
38+
password: ${{ secrets.DOCKERHUB_TOKEN }}
39+
- name: Build and push
40+
uses: docker/build-push-action@v2
41+
with:
42+
context: .
43+
file: Dockerfile
44+
push: ${{ github.event_name != 'pull_request' }}
45+
tags: ${{ steps.meta.outputs.tags }}
46+
labels: ${{ steps.meta.outputs.labels }}
47+
48+
deploy-dev:
49+
runs-on: ubuntu-latest
50+
needs: [build]
51+
steps:
52+
- name: Checkout
53+
uses: actions/checkout@v2
54+
- name: Set K8s context
55+
uses: aliyun/ack-set-context@v1
56+
with:
57+
access-key-id: "${{ secrets.ACCESS_KEY_ID }}"
58+
access-key-secret: "${{ secrets.ACCESS_KEY_SECRET }}"
59+
cluster-id: "${{ env.DEV_ACK_CLUSTER_ID }}"
60+
- name: Install Tools
61+
run: |
62+
wget https://github.com/mikefarah/yq/releases/download/v4.25.1/yq_linux_amd64.tar.gz -O - | tar xz && mv yq_linux_amd64 /usr/local/bin/yq
63+
curl -LO https://storage.googleapis.com/kubernetes-release/release/v1.22.10/bin/linux/amd64/kubectl && chmod +x kubectl && mv kubectl /usr/local/bin/kubectl
64+
- uses: sljeff/secrets2env@main
65+
with:
66+
secrets-json: ${{ toJson(secrets) }}
67+
- env:
68+
IMAGE_TAG_RELEASE: ${{ env.IMAGE_NAME }}:${{ needs.build.outputs.version }}
69+
run: |
70+
sh apply.sh deploy/dev/*
71+
72+
deploy-prod:
73+
if: startsWith(github.ref, 'refs/tags/v')
74+
runs-on: ubuntu-latest
75+
needs: [build, deploy-dev]
76+
steps:
77+
- name: Checkout
78+
uses: actions/checkout@v2
79+
- name: Set K8s context
80+
uses: aliyun/ack-set-context@v1
81+
with:
82+
access-key-id: "${{ secrets.ACCESS_KEY_ID }}"
83+
access-key-secret: "${{ secrets.ACCESS_KEY_SECRET }}"
84+
cluster-id: "${{ env.PROD_ACK_CLUSTER_ID }}"
85+
- name: Install Tools
86+
run: |
87+
wget https://github.com/mikefarah/yq/releases/download/v4.25.1/yq_linux_amd64.tar.gz -O - | tar xz && mv yq_linux_amd64 /usr/local/bin/yq
88+
curl -LO https://storage.googleapis.com/kubernetes-release/release/v1.22.10/bin/linux/amd64/kubectl && chmod +x kubectl && mv kubectl /usr/local/bin/kubectl
89+
- uses: sljeff/secrets2env@main
90+
with:
91+
secrets-json: ${{ toJson(secrets) }}
92+
- env:
93+
IMAGE_TAG_RELEASE: ${{ env.IMAGE_NAME }}:${{ needs.build.outputs.version }}
94+
run: |
95+
sh apply.sh deploy/prod/*

Dockerfile

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
##### BASE
2+
FROM node:18-bullseye-slim as base
3+
4+
# RUN apt-get update || : && apt-get install python3 build-essential git -y
5+
6+
RUN npm i -g pnpm
7+
8+
##### DEPS
9+
FROM base as deps
10+
11+
WORKDIR /app
12+
13+
ADD package.json pnpm-lock.yaml* ./
14+
15+
RUN pnpm i
16+
17+
##### BUILD
18+
FROM deps as build
19+
20+
WORKDIR /app
21+
22+
COPY . .
23+
COPY --from=deps /app/node_modules ./node_modules
24+
25+
ENV NEXT_TELEMETRY_DISABLED 1
26+
ENV NODE_ENV production
27+
ENV BUILD_STEP=1
28+
RUN pnpm build
29+
30+
##### FINAL
31+
FROM base
32+
33+
ENV NODE_ENV=production
34+
WORKDIR /app
35+
36+
COPY --from=build /app/node_modules ./node_modules
37+
COPY --from=build /app/.next ./.next
38+
COPY --from=build /app/public ./public
39+
COPY --from=build /app/package.json ./package.json
40+
COPY --from=build /app/next.config.js ./next.config.js
41+
42+
CMD ["pnpm", "start"]

apply.sh

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
set -e # exit on error
2+
set -x # show command before execute
3+
4+
apply_one() {
5+
export uri="\$uri" # escape
6+
envsubst < $1 > temp.yaml && mv temp.yaml $1
7+
8+
kubectl apply -f $1
9+
}
10+
11+
apply() {
12+
for filename in $@; do
13+
apply_one $filename
14+
done
15+
16+
# rollout status / annotation
17+
for filename in $@; do
18+
yaml_kind=$(yq '.kind' $filename)
19+
if [ "$yaml_kind" = "Deployment" ]; then
20+
ns=$(yq '.metadata.namespace' $filename)
21+
name=$(yq '.metadata.name' $filename)
22+
kubectl -n $ns rollout status -w deploy.apps/$name
23+
fi
24+
done
25+
}
26+
27+
apply $@

deploy/dev/deploy.yaml

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
apiVersion: apps/v1
2+
kind: Deployment
3+
metadata:
4+
name: xchar
5+
namespace: crossbell
6+
spec:
7+
progressDeadlineSeconds: 600
8+
replicas: 1
9+
revisionHistoryLimit: 5
10+
selector:
11+
matchLabels:
12+
app: xchar
13+
tier: api
14+
strategy:
15+
rollingUpdate:
16+
maxSurge: 25%
17+
maxUnavailable: 25%
18+
type: RollingUpdate
19+
template:
20+
metadata:
21+
labels:
22+
app: xchar
23+
tier: api
24+
spec:
25+
containers:
26+
- image: $IMAGE_TAG_RELEASE
27+
imagePullPolicy: Always
28+
name: xchar
29+
envFrom:
30+
- secretRef:
31+
name: xchar
32+
ports:
33+
- containerPort: 3000
34+
protocol: TCP
35+
resources:
36+
requests:
37+
memory: "100Mi"
38+
cpu: "80m"
39+
limits:
40+
memory: "200Mi"
41+
cpu: "200m"
42+
terminationMessagePath: /dev/termination-log
43+
terminationMessagePolicy: File
44+
livenessProbe:
45+
tcpSocket:
46+
port: 3000
47+
initialDelaySeconds: 40
48+
periodSeconds: 20
49+
dnsPolicy: ClusterFirst
50+
restartPolicy: Always
51+
schedulerName: default-scheduler
52+
securityContext: {}
53+
terminationGracePeriodSeconds: 30

deploy/dev/route.yaml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
apiVersion: traefik.containo.us/v1alpha1
2+
kind: IngressRoute
3+
metadata:
4+
name: xchar
5+
namespace: crossbell
6+
spec:
7+
entryPoints:
8+
- web
9+
routes:
10+
- kind: Rule
11+
match: "Host(`$XCHAR_DOMAIN_DEV`)"
12+
services:
13+
- name: xchar
14+
port: 3000

deploy/dev/secrets.yaml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
apiVersion: v1
2+
stringData:
3+
REDIS_URL: $REDIS_URL_DEV
4+
kind: Secret
5+
metadata:
6+
name: xchar
7+
namespace: crossbell
8+
type: Opaque

deploy/dev/svc.yaml

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
apiVersion: v1
2+
kind: Service
3+
metadata:
4+
name: xchar
5+
namespace: crossbell
6+
spec:
7+
type: ClusterIP
8+
selector:
9+
app: xchar
10+
tier: api
11+
ports:
12+
- name: http
13+
protocol: TCP
14+
port: 3000
15+
targetPort: 3000

deploy/prod/deploy.yaml

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
apiVersion: apps/v1
2+
kind: Deployment
3+
metadata:
4+
name: xchar
5+
namespace: crossbell
6+
spec:
7+
progressDeadlineSeconds: 600
8+
replicas: 3
9+
revisionHistoryLimit: 5
10+
selector:
11+
matchLabels:
12+
app: xchar
13+
tier: api
14+
strategy:
15+
rollingUpdate:
16+
maxSurge: 25%
17+
maxUnavailable: 25%
18+
type: RollingUpdate
19+
template:
20+
metadata:
21+
labels:
22+
app: xchar
23+
tier: api
24+
spec:
25+
containers:
26+
- image: $IMAGE_TAG_RELEASE
27+
imagePullPolicy: Always
28+
name: xchar
29+
envFrom:
30+
- secretRef:
31+
name: xchar
32+
ports:
33+
- containerPort: 3000
34+
protocol: TCP
35+
resources:
36+
requests:
37+
memory: "100Mi"
38+
cpu: "80m"
39+
limits:
40+
memory: "200Mi"
41+
cpu: "200m"
42+
terminationMessagePath: /dev/termination-log
43+
terminationMessagePolicy: File
44+
livenessProbe:
45+
tcpSocket:
46+
port: 3000
47+
initialDelaySeconds: 40
48+
periodSeconds: 20
49+
dnsPolicy: ClusterFirst
50+
restartPolicy: Always
51+
schedulerName: default-scheduler
52+
securityContext: {}
53+
terminationGracePeriodSeconds: 30

deploy/prod/route.yaml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
apiVersion: traefik.containo.us/v1alpha1
2+
kind: IngressRoute
3+
metadata:
4+
name: xchar
5+
namespace: crossbell
6+
spec:
7+
entryPoints:
8+
- web
9+
routes:
10+
- kind: Rule
11+
match: "Host(`$XCHAR_DOMAIN`)"
12+
services:
13+
- name: xchar
14+
port: 3000

deploy/prod/secrets.yaml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
apiVersion: v1
2+
stringData:
3+
REDIS_URL: $REDIS_URL
4+
kind: Secret
5+
metadata:
6+
name: xchar
7+
namespace: crossbell
8+
type: Opaque

0 commit comments

Comments
 (0)