目前分類:CI/CD (2)

瀏覽方式: 標題列表 簡短摘要

前一陣子在研究 CI/CD,想到前公司是使用 GitLab 作為版本控管以及 CI/CD 的解決方案,那就來架一台試試看吧。現在要自架 GitLab 服務相當簡單,除了自己準備好環境即可一鍵安裝,使用 docker 快速建立也是個好選擇。以下分別以二種方式進行安裝,順便留個紀錄:

GCP

  • 建立 Compute Engine,GitLab 服務本身算是蠻吃記憶體的,官方建議的配備是四核心 CPU 以及 4GB 以上的 RAM。我開了一台雙核 4GB 的機器個人使用沒有問題,再低可能會有跑不起來的問題,請選用 e2-medium (2 個 vCPU,4 GB 記憶體) 以上等級的規格
  • 根據官方提供的安裝文件進行安裝,這邊以 ubuntu 為例
    # 更新套件來源並安裝相關套件
    sudo apt-get update
    sudo apt-get install curl openssh-server ca-certificates postfix tzdata -y
    
    # 下載 gitlab ce 一鍵安裝包
    curl -sS https://packages.gitlab.com/install/repositories/gitlab/gitlab-ce/script.deb.sh | sudo bash
    
    # 安裝 gitlab ce
    sudo apt-get install gitlab-ce
    
    # 修改 external_url 參數為對外網址
    sudo vi /etc/gitlab/gitlab.rb
    
    # 更新設定並重新啟動 GitLab
    sudo gitlab-ctl reconfigure
  • 第一次 GitLab 連線需要設定 root 的密碼,設定完後就算是建立完成了
  • 因為之後需要串 CI/CD,所以還需要建立 GitLab Runner;它算是實際執行 CI/CD 時的程序。安裝方式也有很多種,這邊我偷懶使用 docker 快速建立,請先確認 docker 已經安裝完成
    # 啟用一個 GitLab Runner 的 docker container
    docker run -d --name gitlab-runner --restart always \
      -v /var/run/docker.sock:/var/run/docker.sock \
      -v /srv/gitlab-runner/config:/etc/gitlab-runner \
      gitlab/gitlab-runner:latest
    
    # 查看列表確認是否啟用成功
    docker ps -a

docker on NAS

  • 這邊以 NAS 為主,去年趁雙 11 特價購入的 NAS 上面,已有多個使用 docker 自架的服務;不過自行升級到 16GB 的記憶體使用率一直很低...明明有多餘的 RAM 卻沒有用到感覺很虧!(咦?)這次試著在上面安裝 GitLab,總算是讓使用率突破 20% 了!以下是 QNAP Container Station,docker-compose.yml 的設定,這邊一併把 GitLab Runner 也包含進去:
    version: '3'
    
    services:
            gitlab:
                    image: gitlab/gitlab-ce:latest
                    container_name: gitlab
                    restart: always
                    environment:
                            GITLAB_OMNIBUS_CONFIG: |
                                    # GitLab 對外網址
                                    external_url "https://gitlab.xxx"
                                    # ssh 對外顯示 port;這邊要特別注意,這個 port 是對外顯示用,所以要跟下面 ports 對應,但實際 docker 內部仍是使用 22 作為 ssh 的 port
                                    gitlab_rails['gitlab_shell_ssh_port'] = 50022
                                    gitlab_rails['lfs_enabled'] = true
                                    gitlab_rails['manage_backup_path'] = true
                                    gitlab_rails['backup_path'] = "/var/opt/gitlab/backups"
                                    gitlab_rails['backup_keep_time'] = 604800
                                    gitlab_rails["time_zone"] = "Asia/Taipei"
                                    # 這邊因為我有用 SSH Tunnel 服務,所以只開 80 port
                                    nginx['listen_port'] = 80
                                    nginx['listen_https'] = false
                                    # GitLab 有內建 letsencrypt 自動更新,不過我有透過 SSH Tunnel 服務已有 https,不確定設定這個是不是有用...
                                    letsencrypt['enable'] = true
                                    # 憑證快到期仍未更新時,發送通知的 email
                                    letsencrypt['contact_emails'] = ['gitlab@gmail.com']
                                    letsencrypt['auto_renew_hour'] = "12"
                                    letsencrypt['auto_renew_minute'] = "30"
                                    letsencrypt['auto_renew_day_of_month'] = "*/7"
    
                    volumes:
                            - ./gitlab/config:/etc/gitlab
                            - ./gitlab/logs:/var/log/gitlab
                            - ./gitlab/data:/var/opt/gitlab
                    ports:
                            - "50443:443"
                            - "50080:80"
                            - "50022:22"
            gitlab-runner:
                    container_name: gitlab-runner
                    image: gitlab/gitlab-runner:latest
                    restart: always
                    volumes:
                            - "/var/run/docker.sock:/var/run/docker.sock"
                            - "./gitlab/runner-config:/etc/gitlab-runner"

shared Runner

  • 接下來我們要註冊一個 Shared runner,讓在這個 GitLab 裡面的專案都可以透過這個 Runner 跑 CI/CD 的 jobs
  • 先進入 GitLab 的 Admin Area,點選 Runner 查看列表
  • 2021-01-17T02-39-15.485Z.png
  • 右上方的 Set up a shared Runner manually 區塊有一些註冊時需要輸入的訊息:2. 是 GitLab 的對外網址 3. 是 token
  • 使用剛剛啟用的 gitlab-runner container
    # 註冊 GitLab Runner
    docker run --rm -it -v /srv/gitlab-runner/config:/etc/gitlab-runner gitlab/gitlab-runner register
     
    Please enter the gitlab-ci coordinator URL (e.g. https://gitlab.com )
    # 這邊輸入 GitLab 的對外網址,參考 Set up a shared Runner manually 2. 的部分
    
    Please enter the gitlab-ci token for this runner
    # 這邊輸入 GitLab 的 token,參考 Set up a shared Runner manually 3. 的部分
    
    Please enter the gitlab-ci description for this runner
    # 這邊可以設定這個 Runner 的說明,非必填
    
    Please enter the gitlab-ci tags for this runner (comma separated):
    # 這邊可以設定這個 Runner 的 tags,非必填
    
    Please enter the executor: ssh, docker+machine, docker-ssh+machine, kubernetes, docker, parallels, virtualbox, docker-ssh, shell:
    docker
    # 選擇這個 Runner 的執行方式,因為我們是使用 docker 啟用,所以這邊要輸入 docker
    docker
    
    Please enter the Docker image (eg. ruby:2.6):
    # 執行時預設啟用的 docekr image,這邊視專案而定,之後在 .gitlab-ci.yml 也可以更改
  • 設定完成後如果沒有問題,就會在 Admin Area > Runner 列表中出現

以上完成安裝 GitLab,以及註冊啟用 GitLab Runner,算是完成 CI/CD 的前置作業,之後要如何設定專案 CI/CD,以及 .gitlab-ci.yml;或許下次有機會再分享?也可以參考一下後面提供的參考資料連結,自行實作看看喔!

參考資料

 ​​

文章標籤

danielhuang030 發表在 痞客邦 留言(0) 人氣()

CI/CD 在整個開發流程中算是最後的環節,如果公司大一些有 MIS/DevOps 部門,這一塊通常會有專業人士處理;工程師寫完程式後只要 merge master branch,理論上就會自動觸發 CI/CD。不過個人專案不比公司產品,不會特別花錢購買完整的服務不說,自己還要學習怎麼「兜」出 CI/CD 的處理流程。市面上有不少提供 CI/CD 服務的廠商,這邊選用的是 CircleCI免費版提供每周 2500 的額度,以及單線程處理。額度的部分老實說我不是很懂他怎麼計算的,至少我目前還沒有遇到超額得情況?單線程處理對於個人專案來說絕對夠用,畢竟只有一個人開發嘛...(汗)

CircleCI 帳號的建立以及與 GitHub 的串接,這部分網路上已有不少前輩分享請自行 Google;這邊我會以個人專案 twitter-test 為例,直接說明 config.yml 的設定配置。以下是 CI/CD 大致的流程:

  1. 把程式碼 merge 到 GitHub 的 master branch,觸發 CircleCI
  2. 開始 build
  3. 透過 docker 建立環境,使用 CircleCI 專用的 .env 以及測試設定,進行單元測試與整合測試
  4. 開始 deploy
  5. 利用在 CircleCI 設定的 SSH Keys,以 ssh 的方式登入 AWS EC2 更新程式碼並執行 deploy.sh
  6. 完成整個 CI/CD 流程

其中 5. 需要在 CircleCI 設定 SSH Keys,設定流程如下:

- 先進入 AWS EC2 主機後,設定一組 CircleCI 用的登入 key

ssh-keygen -t rsa -b 4096 -m pem -C "circleci@twitter-test"
Generating public/private rsa key pair.
Enter file in which to save the key (/home/ubuntu/.ssh/id_rsa): /home/ubuntu/.ssh/id_rsa_circleci
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/ubuntu/.ssh/id_rsa_circleci
Your public key has been saved in /home/ubuntu/.ssh/id_rsa_circleci.pub
The key fingerprint is:
SHA256:HIbCXi1JQmCDNB4EX/L3laqG7VHc8G3z/8mALUcDi6Y circleci@twitter-test
The key's randomart image is:
+---[RSA 4096]----+
|=*=o+ .          |
|ooo* o +   .     |
| .. + * = o.     |
|   . + * B..o    |
|    .   Soo.+o   |
|     o oo  .+o.  |
|    . =E   o +.  |
|     o .    o o..|
|      .        o+|
+----[SHA256]-----+

- 這樣會產生 id_rsa_circleci 與 id_rsa_circleci.pub 2 個檔案,把 id_rsa_circleci.pub 寫入 authorized_keys 中

cat ~/.ssh/id_rsa_circleci.pub >> ~/.ssh/authorized_keys

- 取得 id_rsa_circleci 的 PRIVATE KEY

cat ~/.ssh/id_rsa_circleci

20200909005.jpg

- 接著回到 CircleCI,到「Project Settings」

20200909001.jpg

- 選擇左側「SSH Keys」,下面 Additional SSH Keys 區塊,選擇「Add SSH Key」

20200909003.jpg

- 這邊的 Hostname 就是 AWS EC2 的對外 domain 或是 IP,Private Key 就是剛剛在 id_rsa_circleci 取得的那一長串

20200909004.jpg

- 然後到左側「Environment Variables」,「Add Variable」:

  • HOST_NAME:同上,AWS EC2 的對外 domain 或是 IP
  • USER_NAME:登入 AWS EC2 的帳號,我這邊是使用 ubuntu

20200909002.jpg

到這邊 CircleCI 與 AWS EC2 的設定就完成了,接下來要搭配 config.yml 的設定,說明如下:

version: 2

jobs:
  build:
    # 測試環境是根據我的 docker 檔案設定
    docker:
      - image: circleci/php:7.3-node-browsers
      - image: mysql:5.7
        command: mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci --innodb-use-native-aio=0 --server-id=1 --log_bin=ON
        # 這是測試環境的 MySQL 設定,對應到 .env.circleci 裡面的 DB 設定
        environment:
            MYSQL_HOST: 127.0.0.1
            MYSQL_DB: circleci
            MYSQL_USER: root
            MYSQL_ROOT_PASSWORD: root

    working_directory: ~/app

    steps:
      - checkout
      - run: sudo apt update
      - run: sudo apt install -y libsqlite3-dev zlib1g-dev
      - run: sudo apt install -y mariadb-client
      - run: sudo docker-php-ext-install zip
      - run: sudo docker-php-ext-install pdo_mysql bcmath pcntl mbstring
      - run: sudo composer self-update
      - restore_cache:
          keys:
              - composer-v1-{{ checksum "composer.lock" }}
              - composer-v1-
      # 測試環境是根據 .env.circleci 的設定進行
      - run: cp .env.circleci .env
      - run: composer install -n --ignore-platform-reqs
      - save_cache:
          key: composer-v1-{{ checksum "composer.lock" }}
          paths:
              - vendor
      # 這裡是 node.js 的設定,因為這個專案是純後端,所以都註解掉了
      #- restore_cache: # special step to restore the dependency cache if `package.json` does not change
      #    keys:
      #        - node-v1-{{ checksum "package.json" }}
      #        # fallback to using the latest cache if no exact match is found (See https://circleci.com/docs/2.0/caching/)
      #        - node-v1-
      #- run: npm install
      #- save_cache: # special step to save the dependency cache with the `package.json` cache key template
      #    key: node-v1-{{ checksum "package.json" }}
      #    paths:
      #        - node_modules
      #- run: npm run production
      # 建立資料庫,對應到 .env.circleci 裡面的 DB 設定
      - run:
          name: Mysql database
          command: mysql -h 127.0.0.1 -uroot -proot -e "CREATE DATABASE circleci;"
      - run: php artisan key:generate
      - run: php artisan migrate --env=circleci
      - run: php artisan horizon:install
      - run: php artisan passport:install
      - run:
          name: Run Laravel Server
          command: php artisan serve
          background: true
      # 這邊執行測試時是使用 phpunit.xml.circleci 的設定
      - run: vendor/bin/phpunit -c phpunit.xml.circleci
      # 這邊是 Laravel Dusk 的測試,因為這個專案是純後端,所以都註解掉了
      # - run:
      #     name: Start Chrome Driver
      #     command: ./vendor/laravel/dusk/bin/chromedriver-linux
      #     background: true
      # - run:
      #     name: Run Laravel Dusk Tests
      #     command: php artisan dusk
  deploy:
    machine:
      image: circleci/classic:edge
    steps:
      # 這邊其實很單純的就是 ssh 到 EC2 後,切換目錄,執行 git pull 以及 Shell Script;USER_NAME 與 HOST_NAME 則是對應到我們之前在 CircleCI 設定的環境變數
      - run: ssh ${USER_NAME}@${HOST_NAME} 'cd /var/work/twitter-test/ && git pull origin master && sh ./.circleci/deploy.sh'

workflows:
  version: 2
  main:
    jobs:
      - build:
          filters:
            branches:
              # 限定在 master 變動時,才會 build
              only: master
      - deploy:
          requires:
            - build
          filters:
            branches:
              # 限定在 master 變動時,才會 deploy
              only: master

ssh 進入主機後,因為 Laravel 有不少指令需要執行,我這邊是使用 Shell Script 幫我完成,另外因為我在 EC2 上面跑得是 docker,所以需要透過 docker exec 協助執行;以下是 deploy.sh 的說明:

#!/bin/sh

# container name
container=twitter-test
docker_command="docker exec -i $container"

# shutdown the laravel app
$docker_command php artisan down

# update PHP dependencies
$docker_command composer install  --no-interaction --no-dev --prefer-dist
# --no-interaction Do not ask any interactive question
# --no-dev  Disables installation of require-dev packages.
# --prefer-dist  Forces installation from package dist even for dev versions.

# update database
$docker_command php artisan migrate --force
# --force  Required to run when in production.

# cache boost configuration and routes
$docker_command php artisan cache:clear
$docker_command php artisan config:cache
$docker_command php artisan route:cache

# horizon
$docker_command php artisan horizon:purge
$docker_command php artisan horizon:terminate
$docker_command php artisan queue:restart

# rise from the ashes
$docker_command php artisan up

echo 'Deploy finished.'

全部執行過一遍,大概會在 CircleCI 顯示以下畫面

20200909019.jpg

這些就是最基本的 CI/CD 設定了,雖然很陽春,最後 deploy 是靠 Script 執行,不是正統的分目錄版本有問題還可以緊急切換的那種...(汗)不過對於個人專案來說可以做到自動化處理,也算是有達到目的...吧?僅供參考囉

參考資料

Laravel(EC2)CircleCIによるデプロイ(deploy)の自動化

文章標籤

danielhuang030 發表在 痞客邦 留言(0) 人氣()

Close

您尚未登入,將以訪客身份留言。亦可以上方服務帳號登入留言

請輸入暱稱 ( 最多顯示 6 個中文字元 )

請輸入標題 ( 最多顯示 9 個中文字元 )

請輸入內容 ( 最多 140 個中文字元 )

reload

請輸入左方認證碼:

看不懂,換張圖

請輸入驗證碼