Skip to content

Commit

Permalink
Should fix staging/preview deployments (#103)
Browse files Browse the repository at this point in the history
  • Loading branch information
juancwu authored Dec 9, 2024
2 parents f256fcb + 4630c87 commit bcb6a58
Show file tree
Hide file tree
Showing 6 changed files with 199 additions and 141 deletions.
74 changes: 0 additions & 74 deletions .github/scripts/deploy-preview-backend.sh

This file was deleted.

56 changes: 0 additions & 56 deletions .github/workflows/deploy-preview-backend.yml

This file was deleted.

183 changes: 183 additions & 0 deletions .github/workflows/deploy-staging-backend.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
name: Deploy Staging
on:
workflow_dispatch:
push:
branches: ['main']
paths:
- 'backend/**'
jobs:
deploy:
runs-on: ubuntu-latest
environment: Staging
defaults:
run:
shell: bash
working-directory: backend
steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Create env file
run: |
cat << EOF > .env
APP_ENV=${{ secrets.APP_ENV }}
APP_NAME=${{ secrets.APP_NAME }}
AWS_ACCESS_KEY_ID=${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_REGION=${{ secrets.AWS_REGION }}
AWS_S3_BUCKET=${{ secrets.AWS_S3_BUCKET }}
AWS_SECRET_ACCESS_KEY=${{ secrets.AWS_SECRET_ACCESS_KEY }}
BACKEND_URL=${{ secrets.BACKEND_URL }}
DB_HOST=${{ secrets.DB_HOST }}
DB_NAME=${{ secrets.DB_NAME }}
DB_PASSWORD=${{ secrets.DB_PASSWORD }}
DB_PORT=${{ secrets.DB_PORT }}
DB_SSLMODE=${{ secrets.DB_SSLMODE }}
DB_USER=${{ secrets.DB_USER }}
JWT_SECRET=${{ secrets.JWT_SECRET }}
JWT_SECRET_VERIFY_EMAIL=${{ secrets.JWT_SECRET_VERIFY_EMAIL }}
NOREPLY_EMAIL=${{ secrets.NOREPLY_EMAIL }}
PORT=${{ secrets.PORT }}
POSTGRES_USER=${{ secrets.DB_USER }}
POSTGRES_DB=${{ secrets.DB_NAME }}
POSTGRES_PASSWORD=${{ secrets.DB_PASSWORD }}
RESEND_API_KEY=${{ secrets.RESEND_API_KEY }}
EOF
- name: Setup VPS fingerprint
run: |
mkdir -p ~/.ssh
echo "${{ secrets.VPS_KEY }}" > ~/.ssh/id_rsa
chmod 600 ~/.ssh/id_rsa
echo "${{ secrets.VPS_IP }} ${{ secrets.VPS_FINGERPRINT }}" >> ~/.ssh/known_hosts
- name: Setup Rsync
uses: GuillaumeFalourd/[email protected]

- name: Setup VPS File System Tree
uses: appleboy/[email protected]
with:
host: ${{ secrets.VPS_IP }}
username: ${{ secrets.VPS_USER }}
key: ${{ secrets.VPS_KEY }}
script: |
mkdir -p $HOME/staging/migrations
- name: Upload .env
run: |
rsync -avz --progress .env ${{ secrets.VPS_USER }}@${{ secrets.VPS_IP }}:~/staging/
- name: Upload Migrations
run: |
rsync -avz --delete --progress .sqlc/migrations/ ${{ secrets.VPS_USER }}@${{ secrets.VPS_IP }}:~/staging/migrations/
- name: Boot Postgres and Run Migrations
uses: appleboy/[email protected]
env:
DB_NAME: ${{ secrets.DB_NAME }}
DB_PASSWORD: ${{ secrets.DB_PASSWORD }}
DB_PORT: ${{ secrets.DB_PORT }}
DB_SSLMODE: ${{ secrets.DB_SSLMODE }}
DB_USER: ${{ secrets.DB_USER }}
APP_NAME: ${{ secrets.APP_NAME }}
APP_ENV: ${{ secrets.APP_ENV }}
with:
host: ${{ secrets.VPS_IP }}
username: ${{ secrets.VPS_USER }}
key: ${{ secrets.VPS_KEY }}
envs: DB_NAME,DB_PASSWORD,DB_PORT,DB_SSLMODE,DB_USER,APP_NAME,APP_ENV
script: |
cd $HOME/staging
POSTGRES_DATA_DIR="$HOME/staging/postgres"
mkdir -p $POSTGRES_DATA_DIR
POSTGRES_CONTAINER="$APP_NAME-$APP_ENV-postgres"
if ! docker ps --filter "name=$POSTGRES_CONTAINER" --format '{{.Names}}' | grep -q "^$POSTGRES_CONTAINER"; then
echo "PostgreSQL container not found. Starting new container..."
docker stop $POSTGRES_CONTAINER || true
docker rm $POSTGRES_CONTAINER || true
docker run -d \
--name "$POSTGRES_CONTAINER" \
-p "$DB_PORT:5432" \
-v "$POSTGRES_DATA_DIR:/var/lib/postgresql/data" \
--env POSTGRES_USER="${{ secrets.DB_USER }}" \
--env POSTGRES_PASSWORD="${{ secrets.DB_PASSWORD }}" \
--env POSTGRES_DB="${{ secrets.DB_NAME }}" \
postgres:16
# Wait for PostgreSQL to be ready
echo "Waiting for PostgreSQL to be ready..."
RETRY_COUNT=0
MAX_RETRIES=10
while ! docker exec "$POSTGRES_CONTAINER" pg_isready -q; do
RETRY_COUNT=$((RETRY_COUNT + 1))
if [ $RETRY_COUNT -eq $MAX_RETRIES ]; then
echo "Error: PostgreSQL failed to start after $MAX_RETRIES attempts"
exit 1
fi
echo "Waiting for PostgreSQL to be ready..."
sleep 1
done
echo "Postgres is ready!"
else
echo "PostgreSQL container is already running"
fi
goose fix -dir $HOME/staging/migrations
goose -dir $HOME/staging/migrations postgres \
"postgres://$DB_USER:$DB_PASSWORD@localhost:$DB_PORT/$DB_NAME?sslmode=$DB_SSLMODE" up
- name: Build Docker Image
run: |
docker build -t ${{ secrets.APP_NAME }}-${{ secrets.APP_ENV }}:latest .
docker save -o image.tar ${{ secrets.APP_NAME }}-${{ secrets.APP_ENV }}:latest
- name: Upload Docker Image
run: |
rsync -avz image.tar ${{ secrets.VPS_USER }}@${{ secrets.VPS_IP }}:~/staging/
- name: Deploy Go App on VPS
uses: appleboy/[email protected]
env:
DB_NAME: ${{ secrets.DB_NAME }}
DB_PASSWORD: ${{ secrets.DB_PASSWORD }}
DB_PORT: ${{ secrets.DB_PORT }}
DB_SSLMODE: ${{ secrets.DB_SSLMODE }}
DB_USER: ${{ secrets.DB_USER }}
APP_NAME: ${{ secrets.APP_NAME }}
APP_ENV: ${{ secrets.APP_ENV }}
with:
host: ${{ secrets.VPS_IP }}
username: ${{ secrets.VPS_USER }}
key: ${{ secrets.VPS_KEY }}
envs: DB_NAME,DB_PASSWORD,DB_PORT,DB_SSLMODE,DB_USER,APP_NAME,APP_ENV
script: |
cd $HOME/staging
echo "Stopping and removing existing container if present..."
CONTAINER="$APP_NAME-$APP_ENV"
docker stop $CONTAINER || true
docker rm $CONTAINER || true
echo "Loading pre-built docker image..."
docker load -i image.tar
echo "Starting new application container..."
docker run -d \
--name $CONTAINER \
--env-file .env \
--network=host --add-host=host.docker.internal:host-gateway \
"$APP_NAME-$APP_ENV:latest"
echo "Done: Staging Deployment"
- name: Post Deployment Clean Up on VPS
uses: appleboy/[email protected]
with:
host: ${{ secrets.VPS_IP }}
username: ${{ secrets.VPS_USER }}
key: ${{ secrets.VPS_KEY }}
script: |
rm -rf $HOME/staging/migrations
rm -f $HOME/staging/image.tar
rm -f $HOME/staging/.env
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ on:
jobs:
build-and-deploy-frontend:
runs-on: ubuntu-latest
environment: Staging
defaults:
run:
shell: bash
Expand Down Expand Up @@ -37,15 +38,20 @@ jobs:
restore-keys: |
${{ runner.os }}-pnpm-store-
- name: Install dependencies
run: cd frontend && pnpm install --frozen-lockfile
run: pnpm install --frozen-lockfile
- name: Build environment
run: |
cat << EOF > .env
VITE_API_URL=${{ secrets.BACKEND_URL }}/api/v1
EOF
- name: Build
run: cd frontend && pnpm build
run: pnpm build
- name: Deploy to server
uses: appleboy/scp-action@master
with:
host: ${{ secrets.PREVIEW_SERVER_IP }}
username: ${{ secrets.PREVIEW_USER }}
key: ${{ secrets.PREVIEW_SERVER_SSH_KEY }}
source: "frontend/dist/"
target: "${{ secrets.TARGET_DIR }}"
strip_components: 1
host: ${{ secrets.VPS_IP }}
username: ${{ secrets.VPS_USER }}
key: ${{ secrets.VPS_KEY }}
source: "frontend/dist/*"
target: "${{ secrets.FE_DIR }}"
strip_components: 2
3 changes: 1 addition & 2 deletions backend/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,5 @@ RUN apk --no-cache add ca-certificates
WORKDIR /root/
COPY --from=builder /app/app .
RUN mkdir -p static/dist
EXPOSE 6969
ENV APP_ENV="production"

CMD ["./app"]
2 changes: 1 addition & 1 deletion backend/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import (
func main() {
zerolog.TimeFieldFormat = zerolog.TimeFormatUnix

if os.Getenv("APP_ENV") != common.PRODUCTION_ENV {
if os.Getenv("APP_ENV") == common.DEVELOPMENT_ENV {
if err := godotenv.Load(); err != nil {
log.Fatal().Err(err).Msg("failed to load .env")
}
Expand Down

0 comments on commit bcb6a58

Please sign in to comment.