• Что бы вступить в ряды "Принятый кодер" Вам нужно:
    Написать 10 полезных сообщений или тем и Получить 10 симпатий.
    Для того кто не хочет терять время,может пожертвовать средства для поддержки сервеса, и вступить в ряды VIP на месяц, дополнительная информация в лс.

  • Пользаватели которые будут спамить, уходят в бан без предупреждения. Спам сообщения определяется администрацией и модератором.

  • Гость, Что бы Вы хотели увидеть на нашем Форуме? Изложить свои идеи и пожелания по улучшению форума Вы можете поделиться с нами здесь. ----> Перейдите сюда
  • Все пользователи не прошедшие проверку электронной почты будут заблокированы. Все вопросы с разблокировкой обращайтесь по адресу электронной почте : info@guardianelinks.com . Не пришло сообщение о проверке или о сбросе также сообщите нам.

🚀Deploying a Node.js App to Google Cloud VM with GitHub Actions CI/CD Setup

Sascha Оффлайн

Sascha

Заместитель Администратора
Команда форума
Администратор
Регистрация
9 Май 2015
Сообщения
1,605
Баллы
155
🧩 Introduction


This guide walks you through building a complete CI/CD pipeline that deploys a Node.js app from GitHub to a Google Compute Engine (GCE) Virtual Machine.

  1. Every time you push code to the main branch:
  2. GitHub Actions builds & tests your code
  3. Creates a zip artifact
  4. Securely copies it to your GCE VM
  5. Deploys and restarts the app using systemd
  6. Validates health automatically

You’ll end up with a zero-click deployment process.

⚙ Step 1 — Create a Sample Node.js App


Create your project:


mkdir sample-gce-app && cd sample-gce-app
npm init -y




Add a minimal web server:


mkdir src
cat > src/index.js <<'EOF'
const http = require('http');
const PORT = process.env.PORT || 3000;

const server = http.createServer((req, res) => {
if (req.url === '/health') {
res.writeHead(200, {'Content-Type': 'application/json'});
res.end(JSON.stringify({status: 'ok'}));
} else {
res.writeHead(200);
res.end('Hello from GCE VM 🚀');
}
});

server.listen(PORT, () => console.log(`Server running on port ${PORT}`));
EOF




Add package.json scripts:


npm install
npm set-script start "node src/index.js"
npm set-script test "echo 'No tests yet'"




Then create a package-lock.json:


npm install




✅ Commit both files — package.json and package-lock.json.


Пожалуйста Авторизируйтесь или Зарегистрируйтесь для просмотра скрытого текста.



You can use below source code repository


Пожалуйста Авторизируйтесь или Зарегистрируйтесь для просмотра скрытого текста.



☁ Step 2 — Create a Google Cloud VM



Пожалуйста Авторизируйтесь или Зарегистрируйтесь для просмотра скрытого текста.



Go to Google Cloud Console → Compute Engine → Create VM Instance

Choose:

  • OS: Ubuntu 22.04 LTS
  • Machine: e2-micro (for demo)
  • Allow HTTP/HTTPS traffic

Generate a deploy key:


ssh-keygen -t rsa -b 4096 -f ~/.ssh/gcpdeploy_key




Copy the public key (~/.ssh/gcpdeploy_key.pub) into the VM → Edit → SSH Keys.

Note the external IP.


Пожалуйста Авторизируйтесь или Зарегистрируйтесь для просмотра скрытого текста.



🧰 Step 3 — Prepare Your VM


SSH into your VM:


ssh -i ~/.ssh/gcpdeploy_key ubuntu@<your-external-ip>




Install dependencies:


curl -fsSL

Пожалуйста Авторизируйтесь или Зарегистрируйтесь для просмотра скрытого текста.

| sudo -E bash -
sudo apt install -y nodejs unzip




Create app directory:


sudo mkdir -p /opt/myapp
sudo chown -R ubuntu:ubuntu /opt/myapp



⚙ Step 4 — Create a systemd Service


Create /etc/systemd/system/myapp.service:


[Unit]
Description=Sample Node App
After=network.target

[Service]
User=ubuntu
WorkingDirectory=/opt/myapp/current
ExecStart=/usr/bin/node /opt/myapp/current/src/index.js
Restart=always
RestartSec=10
Environment=PORT=3000
StandardOutput=append:/var/log/myapp.log
StandardError=append:/var/log/myapp.err

[Install]
WantedBy=multi-user.target




Enable service:


sudo systemctl daemon-reload
sudo systemctl enable myapp



🔐 Step 5 — Configure GitHub Secrets


Go to Settings → Secrets and variables → Actions → New repository secret

Secret NameExample Value
GCE_SSH_PRIVATE_KEY(contents of ~/.ssh/gcpdeploy_key)
GCE_SSH_USERubuntu
GCE_SSH_HOST34.xxx.xxx.xxx
GCE_REMOTE_DIR/opt/myapp
GCE_SSH_PORT22


Пожалуйста Авторизируйтесь или Зарегистрируйтесь для просмотра скрытого текста.



⚙ Step 6 — GitHub Actions Workflow


Create .github/workflows/ci-cd.yml:


name: CI/CD → GCE VM

on:
push:
branches:
- main

jobs:
build-test-deploy:
runs-on: ubuntu-latest
env:
REMOTE_DIR: ${{ secrets.GCE_REMOTE_DIR }}
SSH_USER: ${{ secrets.GCE_SSH_USER }}
SSH_HOST: ${{ secrets.GCE_SSH_HOST }}
SSH_PORT: ${{ secrets.GCE_SSH_PORT || '22' }}

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: '18'

- name: Verify lock file
run: |
if [ ! -f package-lock.json ]; then
echo "No lockfile found — generating one."
npm install
fi

- name: Install dependencies
run: npm ci --prefer-online --no-audit

- name: Run tests
run: npm test

- name: Create deployment artifact
run: |
mkdir -p build
cp package*.json build/
cp -r src build/
cd build && zip -r ../artifact.zip .
ls -lh ../artifact.zip

- name: Configure SSH key
run: |
mkdir -p ~/.ssh
echo "${{ secrets.GCE_SSH_PRIVATE_KEY }}" > ~/.ssh/id_rsa
chmod 600 ~/.ssh/id_rsa
ssh-keyscan -p ${{ env.SSH_PORT }} ${{ env.SSH_HOST }} >> ~/.ssh/known_hosts

- name: Copy artifact to GCE VM
uses: appleboy/scp-action@v0.1.7
with:
host: ${{ env.SSH_HOST }}
username: ${{ env.SSH_USER }}
port: ${{ env.SSH_PORT }}
key: ${{ secrets.GCE_SSH_PRIVATE_KEY }}
source: "artifact.zip"
target: "${{ env.REMOTE_DIR }}"

- name: Deploy & restart service
uses: appleboy/ssh-action@v0.1.8
with:
host: ${{ env.SSH_HOST }}
username: ${{ env.SSH_USER }}
port: ${{ env.SSH_PORT }}
key: ${{ secrets.GCE_SSH_PRIVATE_KEY }}
script: |
set -e
echo "Deploying new version to ${REMOTE_DIR}"
cd "${REMOTE_DIR}"
mkdir -p releases
TIMESTAMP=$(date +%s)
mkdir -p releases/$TIMESTAMP
unzip -o artifact.zip -d releases/$TIMESTAMP
rm -rf current_prev || true
[ -d current ] && mv current current_prev || true
mv releases/$TIMESTAMP current
cd current
npm ci --omit=dev || npm install --omit=dev
sudo systemctl daemon-reload
sudo systemctl restart myapp || (echo "Restart failed, rolling back..." && sudo systemctl stop myapp && rm -rf current && mv current_prev current && sudo systemctl start myapp)
sleep 3
curl -f

Пожалуйста Авторизируйтесь или Зарегистрируйтесь для просмотра скрытого текста.

|| echo "Health check failed"



🧾 Step 7 — Trigger a Deployment


Commit and push:


git add .
git commit -m "Enable full CI/CD deployment"
git push origin main




GitHub Actions will:

  1. Checkout & build
  2. Install deps from package-lock.json
  3. Run tests
  4. Zip app
  5. Upload via SCP
  6. Unzip on GCE
  7. Restart myapp.service
  8. Validate health


Пожалуйста Авторизируйтесь или Зарегистрируйтесь для просмотра скрытого текста.



🧩 Step 8 — Verify on VM


Check service:


sudo systemctl status myapp




View logs:


tail -f /var/log/myapp.log




App should be live at:


http://<your-external-ip>:3000



🧠 Rollback Logic Built-In


If the new version fails to start, the script automatically:

  • Moves current_prev back to current
  • Restarts the last working version
⚡ Bonus Improvements


✅ Add npm caching:


- name: Cache npm modules
uses: actions/cache@v4
with:
path: ~/.npm
key: ${{ runner.os }}-npm-${{ hashFiles('package-lock.json') }}
restore-keys: |
${{ runner.os }}-npm-




✅ Log rotation:


sudo nano /etc/logrotate.d/myapp

/var/log/myapp.log /var/log/myapp.err {
weekly
rotate 4
compress
missingok
notifempty
}





🎯 Final Directory Layout on GCE


/opt/myapp/
├── artifact.zip
├── current/ ← active release
│ ├── src/
│ └── package.json
├── current_prev/ ← backup previous release
└── releases/
└── <timestamp>/



✅ Summary

StageAction
Build npm ci using package-lock.json
TestRun Jest/unit tests
ArtifactCreate artifact.zip
DeployCopy to GCE via SSH
RollbackAuto restore previous release if failed
Validatecurl

Пожалуйста Авторизируйтесь или Зарегистрируйтесь для просмотра скрытого текста.

PersistentManaged by systemd
🌟 Final Result


Your pipeline is now:

  • Secure (SSH key-based deploys)
  • Repeatable (lockfile ensures consistent builds)
  • Resilient (automatic rollback)
  • Continuous (Git push = deploy)
  • Observable (logs + health checks)

🌟 Thanks for reading! If this post added value, a like ❤, follow, or share would encourage me to keep creating more content.


— Latchu | Senior DevOps & Cloud Engineer

☁ AWS | GCP | ☸ Kubernetes | 🔐 Security | ⚡ Automation
📌 Sharing hands-on guides, best practices & real-world cloud solutions



Источник:

Пожалуйста Авторизируйтесь или Зарегистрируйтесь для просмотра скрытого текста.

 
Вверх Снизу