initial commit
This commit is contained in:
156
.github/workflows/deploy.yml
vendored
Normal file
156
.github/workflows/deploy.yml
vendored
Normal file
@@ -0,0 +1,156 @@
|
||||
name: Deploy SiliconPin
|
||||
on:
|
||||
push:
|
||||
branches: [ main ] # Change this to match your main branch name if different
|
||||
workflow_dispatch: # Allows manual workflow runs
|
||||
|
||||
jobs:
|
||||
build-and-deploy:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '20'
|
||||
|
||||
- name: Cache Yarn dependencies
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
~/.cache/yarn
|
||||
node_modules
|
||||
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-yarn-
|
||||
|
||||
- name: Install dependencies
|
||||
run: yarn install --frozen-lockfile
|
||||
|
||||
- name: Create .env file
|
||||
run: |
|
||||
echo "Creating .env file with secrets..."
|
||||
echo "MONGODB_URI=${{ secrets.MONGODB_URI }}" > .env
|
||||
echo "REDIS_URL=${{ secrets.REDIS_URL }}" >> .env
|
||||
echo "SESSION_SECRET=${{ secrets.SESSION_SECRET }}" >> .env
|
||||
echo "JWT_SECRET=${{ secrets.JWT_SECRET }}" >> .env
|
||||
echo "JWT_REFRESH_SECRET=${{ secrets.JWT_REFRESH_SECRET }}" >> .env
|
||||
echo "GOOGLE_CLIENT_ID=${{ secrets.GOOGLE_CLIENT_ID }}" >> .env
|
||||
echo "GOOGLE_CLIENT_SECRET=${{ secrets.GOOGLE_CLIENT_SECRET }}" >> .env
|
||||
echo "GOOGLE_REDIRECT_URI=${{ secrets.GOOGLE_REDIRECT_URI }}" >> .env
|
||||
echo "NEXT_PUBLIC_APP_URL=${{ secrets.NEXT_PUBLIC_APP_URL }}" >> .env
|
||||
echo "NODE_ENV=production" >> .env
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Build Docker image
|
||||
uses: docker/build-push-action@v5
|
||||
with:
|
||||
context: .
|
||||
push: false
|
||||
tags: siliconpin:latest
|
||||
cache-from: type=gha
|
||||
cache-to: type=gha,mode=max
|
||||
outputs: type=docker,dest=/tmp/siliconpin-image.tar
|
||||
|
||||
- name: Load Docker image
|
||||
run: docker load -i /tmp/siliconpin-image.tar
|
||||
|
||||
- name: Set up SSH
|
||||
uses: shimataro/ssh-key-action@v2
|
||||
with:
|
||||
key: ${{ secrets.SSH_PRIVATE_KEY }}
|
||||
known_hosts: 'just-a-placeholder'
|
||||
|
||||
- name: Add remote host to known hosts
|
||||
run: |
|
||||
mkdir -p ~/.ssh
|
||||
echo "Adding ${{ secrets.SSH_HOST }} to known hosts..."
|
||||
ssh-keyscan -H ${{ secrets.SSH_HOST }} >> ~/.ssh/known_hosts
|
||||
chmod 600 ~/.ssh/known_hosts
|
||||
|
||||
- name: Compress Docker image
|
||||
run: |
|
||||
echo "Compressing Docker image..."
|
||||
gzip /tmp/siliconpin-image.tar
|
||||
mv /tmp/siliconpin-image.tar.gz siliconpin-image.tar.gz
|
||||
|
||||
- name: Transfer Docker image to server
|
||||
run: |
|
||||
echo "Transferring Docker image to server..."
|
||||
scp -o StrictHostKeyChecking=no siliconpin-image.tar.gz ${{ secrets.SSH_USER }}@${{ secrets.SSH_HOST }}:/root/services/siliconpin-image.tar.gz
|
||||
scp -o StrictHostKeyChecking=no docker-compose.yml ${{ secrets.SSH_USER }}@${{ secrets.SSH_HOST }}:/root/services/siliconpin/docker-compose.yml
|
||||
|
||||
- name: Deploy to production
|
||||
run: |
|
||||
ssh -o StrictHostKeyChecking=no ${{ secrets.SSH_USER }}@${{ secrets.SSH_HOST }} << 'EOF'
|
||||
# Force using bash instead of fish
|
||||
bash -c '
|
||||
# Navigate to the services directory
|
||||
cd /root/services/
|
||||
|
||||
# Create siliconpin directory if it doesn not exist
|
||||
mkdir -p siliconpin
|
||||
cd siliconpin
|
||||
|
||||
# Stop the current container
|
||||
docker compose down || true
|
||||
|
||||
# Load the new Docker image
|
||||
echo "Loading Docker image..."
|
||||
docker load < /root/services/siliconpin-image.tar.gz
|
||||
|
||||
# Remove the transferred image file
|
||||
rm -f /root/services/siliconpin-image.tar.gz
|
||||
|
||||
# Start the container using the new image
|
||||
echo "Starting container..."
|
||||
docker compose up -d
|
||||
|
||||
# Wait for container to be fully running
|
||||
echo "Waiting for container to be ready..."
|
||||
attempt=1
|
||||
max_attempts=30
|
||||
|
||||
until [ $attempt -gt $max_attempts ] || docker container inspect siliconpin --format="{{.State.Running}}" 2>/dev/null | grep -q "true"; do
|
||||
echo "Attempt $attempt/$max_attempts: Container not ready yet, waiting..."
|
||||
sleep 2
|
||||
attempt=$((attempt+1))
|
||||
done
|
||||
|
||||
if [ $attempt -gt $max_attempts ]; then
|
||||
echo "Container failed to start properly within time limit!"
|
||||
docker compose logs
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Further verification of application health
|
||||
echo "Verifying application health..."
|
||||
timeout=120
|
||||
start_time=$(date +%s)
|
||||
end_time=$((start_time + timeout))
|
||||
while [ $(date +%s) -lt $end_time ]; do
|
||||
if curl -s http://localhost:4023/ > /dev/null; then
|
||||
echo "Application is responding!"
|
||||
break
|
||||
fi
|
||||
echo "Waiting for application to respond..."
|
||||
sleep 10
|
||||
done
|
||||
|
||||
if ! curl -s http://localhost:4023/ > /dev/null; then
|
||||
echo "Application failed to respond within timeout!"
|
||||
docker compose logs
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Clean up is already done above
|
||||
|
||||
# Verify deployment
|
||||
echo "Deployment successful! Container is running and application is responding."
|
||||
docker ps | grep siliconpin
|
||||
'
|
||||
EOF
|
||||
Reference in New Issue
Block a user