利用 Gitlab CI/CD 部署專案到 GCP virtual machine

前言

本篇將分享如下:

  1. 利用 gcloud 開立一台 GCP instance
  2. 如何利用 gcloudinstance 上匯入 ssh key
  3. 利用 Daemon 使服務常駐
  4. 利用 gitlab pusher 部署專案到 GCP virtual machine

環境建立

開啟一台 GCP 虛擬機

以下是個人做法,不需要照做

  • Ray 使用 Mac 所以我在本地端安裝了 Google Cloud SDK, 安裝方式可以參考官方文件
  • 建立一台 VM
    1. 建立一台機器, 叫做 example-instance-1
    2. 開機碟的空間為 10GB
    3. ubuntu-os-cloud, 來 pull 我們需要的 image
    4. 我們使用 ubuntu-1804-ltsimage 版本, 這會自動使用這個版本的最新版
    5. 硬碟類型為 pd-stand, 不知道類型可以跑 gcloud compute disk-types list 來看看
    6. 機器型號為 f1-micro, 不知道類型可以跑 gcloud compute machine-types list 來看看
    7. tags 用來當作該 instance 的一個識別,等等開防火牆的時候會用到
    8. zone 指定該 instance 的地區, 有些資源只有相同 zone 或者 region 可以取用,要注意

如下:

gcloud compute instances create example-instance-1 \
--image-project=ubuntu-os-cloud \
--image-family=ubuntu-1804-lts \
--boot-disk-size=10GB \
--boot-disk-type=pd-standard \
--machine-type=f1-micro \
--tags=example-instance-1,http-server,https-server \
--zone=asia-east1-a

開啟後,我們先來產 key

ssh-keygen -t rsa -b 4096 -C "root@example"

假設 key 的名稱為 example

cat example.pub > instanceSSHConfig && vim instanceSSHList

在最前面加上 root, 格式如下:

[USERNAME]:ssh-rsa [KEY] [USERNAME]

我們只有一把 key

獲得 instance 名稱

gcloud compute instances list

新增 public keyinstance
(這邊請注意,這個指令會替換掉這個 instance 在 GCP 的 SSH key, 換言之,這個檔案裡面沒有的 key 都會消失)

gcloud compute instances add-metadata instanceName --metadata-from-file ssh-keys=instanceSSHList

安裝

以下主要是安裝 nvm, node 版本v12.1.0, 以及 npm, 細節可以參考官方文件

apt-get update -y && apt-get install curl -y && curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.34.0/install.sh | bash && export NVM_DIR="$HOME/.nvm" && [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" && [ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion" && nvm install v12.1.0 && apt-get install npm -y

Daemon

接下來,
以下為 Daemon 設定, 我們將使用 Daemon 來幫我們跑我們的服務,並且讓我們的服務在斷開的時候可以自動重啟

sudo vim /etc/init.d/serviceName

#!/bin/sh
### BEGIN INIT INFO
# Provides: yourServiceName (optional)
# Required-Start: $remote_fs $syslog
# Required-Stop: $remote_fs $syslog
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: Start daemon at boot time
# Description: Enable service provided by daemon.
### END INIT INFO

dir="yourProjectLocation"
cmd="theCommandItRequiresToStartYourService"
user="root"

name=`basename $0`
pid_file="/var/run/$name.pid"
stdout_log="/var/log/$name.log"
stderr_log="/var/log/$name.log"

get_pid() {
cat "$pid_file"
}

is_running() {
[ -f "$pid_file" ] && ps -p `get_pid` > /dev/null 2>&1
}

case "$1" in
start)
if is_running; then
echo "Already started"
else
echo "Starting $name"
cd "$dir"
export NODE_ENV=test
if [ -z "$user" ]; then
sudo $cmd >> "$stdout_log" 2>> "$stderr_log" &
else
sudo -u "$user" $cmd >> "$stdout_log" 2>> "$stderr_log" &
fi
echo $! > "$pid_file"
if ! is_running; then
echo "Unable to start, see $stdout_log and $stderr_log"
exit 1
fi
fi
;;
stop)
if is_running; then
echo -n "Stopping $name.."
kill `get_pid`
for i in 1 2 3 4 5 6 7 8 9 10
# for i in `seq 10`
do
if ! is_running; then
break
fi

echo -n "."
sleep 1
done
echo

if is_running; then
echo "Not stopped; may still be shutting down or shutdown may have failed"
exit 1
else
echo "Stopped"
if [ -f "$pid_file" ]; then
rm "$pid_file"
fi
fi
else
echo "Not running"
fi
;;
restart)
$0 stop
if is_running; then
echo "Unable to stop, will not attempt to start"
exit 1
fi
$0 start
;;
status)
if is_running; then
echo "Running"
else
echo "Stopped"
exit 1
fi
;;
*)
echo "Usage: $0 {start|stop|restart|status}"
exit 1
;;
esac

exit 0
  • 若發現找不到 service 的話,那需要重新載入 daemon

    sudo systemctl daemon-reload
  • 記得更改權限,讓 deamon 可以執行

    sudo chmod 755 serviceName
  • 開啟自動重啟,當 VM 重啟時,服務會跟著重啟

    sudo systemctl enable serviceName
  • Daemon 的名稱在此範例中,會設置的跟專案名稱一樣

CI/CD

Gitlab variables setting

  • 我們將使用 Gitlab 的 pusher 來做 CI/CD 的部分,所以這邊先建立一組 ssh key, 並且在 gitlab 中設定為 $SSH_PRIVATE_KEY
ssh-keygen -t rsa -b 4096 -C "root@deploy"

Gitlab yaml config file

下面我們會開始設定 Gitlab 的 pusher config yaml 檔案
在我們的專案中:

vim .gitlab-ci.yml

# This file is a template, and might need editing before it works on your project.
# Official framework image. Look for the different tagged releases at:
# https://hub.docker.com/r/library/node/tags/
# 在 Docker 內部,我們要使用的環境 image
image: node:8

# This folder is cached between builds
# http://docs.gitlab.com/ce/ci/yaml/README.html#cache
# cache 可以讓我們使用在所有的 build
cache:
paths:
- node_modules/

stages:
- build
- deploy

# 只是個名字
npm-build:
stage: build
script:
# 刪掉 node_modules, 安裝最新版的 npm, 並更新 project 裡頭的 npm 套件
- rm -rf node_modules/ && npm i npm@latest -g && npm install

# 只是個名字
depoly-test:
# 將在 `deploy` stage 做以下的事
stage: deploy
script:
# cfr. https://docs.gitlab.com/ee/ci/ssh_keys/README.html
# Install ssh-agent if not already installed, it is required by Docker.
# (change apt-get to yum if you use a CentOS-based image)
# 如果 ssh-agent 不存在,更新 apt-get 並且安裝 openssh-client
- 'which ssh-agent || ( apt-get update -y && apt-get install openssh-client -y )'

# Run ssh-agent (inside the build environment)
# 當運行 ssh-agent -s 時,會輸出一些 command, 但是他們並還沒有被執行,所以必須使用 eval ,他可以用來執行迭代運算
- eval $(ssh-agent -s)

# Add the SSH key stored in SSH_PRIVATE_KEY variable to the agent store
# 將 $SSH_PRIVATE_KEY 加到 ssh agent
- ssh-add <(echo "$SSH_PRIVATE_KEY")

# For Docker builds disable host key checking. Be aware that by adding that
# you are suspectible to man-in-the-middle attacks.
# WARNING: Use this only with the Docker executor, if you use it with shell
# you will overwrite your user's SSH config.
#- mkdir -p ~/.ssh
#- '[[ -f /.dockerenv ]] && echo -e "Host *\n\tStrictHostKeyChecking no\n\n" > ~/.ssh/config'
# In order to properly check the server's host key, assuming you created the
# SSH_SERVER_HOSTKEYS variable previously, uncomment the following two lines
# instead.

# 在 docker container 中,建立 .ssh 資料夾, 並設立權限
- mkdir -m 700 -p /root/.ssh

# 使用 gz 格式來將位於當層的專案資料夾整個壓縮,並將壓縮檔丟到上一層目錄去
- tar zcf ../$CI_PROJECT_NAME.tar.gz ./

# 將壓縮檔丟到指定機器上的指定目錄
- scp -o StrictHostKeyChecking=no ../$CI_PROJECT_NAME.tar.gz root@35.201.171.244:/locationYouPrefer

# 接下來,我們利用 ssh 到指定的機器,然後開始做以下的事
# 建立一個跟專案同名的資料夾
# 將剛剛打包好的檔案,解壓縮到這個資料夾內,並不顯示解壓縮訊息
# 更改專案資料夾的權限
# 進到資料夾中, npm rebuild, 並且打開事先設定好的 daemon service
- ssh root@yourIP "rm -rf /locationYouPrefer/$CI_PROJECT_NAME && mkdir -p locationYouPrefer/$CI_PROJECT_NAME && tar zxf locationYouPrefer/$CI_PROJECT_NAME.tar.gz -C locationYouPrefer/$CI_PROJECT_NAME && chmod -R 655 locationYouPrefer/$CI_PROJECT_NAME && cd locationYouPrefer/$CI_PROJECT_NAME && npm rebuild && /etc/init.d/$CI_PROJECT_NAME restart"

# 以上的 deploy stage 唯有在你指定的 branch 觸發
only:
- branchYouPrefer

結論

到這邊,當我們 git push 到指定的 branch 時,就會觸發 gitlabpusher 來達成自動部署。

gcloud CLI 用法 Node.js 學習筆記

留言

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×