Chuyển tới nội dung

Thực hành CI/CD trên gitlab local

Trên gitlab.local đã có username: diendtgroup: beobeo

Bước 1. Tạo dự án
Vào Admin Area -> Overview -> Project -> New Project

Create New Blank Project -> Nhập tên Projet -> Chọn Group hoặc User -> Chọn Visibility Level -> Tick hoặc Untick vào Initialize repository with a README -> Create Project

Bước 2. Clone dự án từ github và khởi tạo dự án

cd <thư mục chứa các dự án>
git clone https://gitlab.com/nhanfu/core2 corejs2
cd corejs2
git config --local user.name "Dien Do"
git config --local user.email "[email protected]"
git remote rename origin old-origin
git remote add origin http://gitlab.local/beobeo/corejs.git
git push --set-upstream origin --all
git push --set-upstream origin --tags

Bước 3. Đăng ký Gitlab-Runner

Đăng nhập vào GitLab và đi đến: Admin Area > CI/CD > Runners.

Click vào Create Instance Runner

Tại đây, bạn nhập tags, Descriptions và bấm Create Runner

Chọn Platform và gõ lệnh theo hướng dẫn vào máy cài gitlab-runner

Tuy nhên gitlab-runner trong bài lab này được cài từ docker nên lệnh có sự thay đổi một chút như sau:

cd <thu muc chua file docker-compose>
docker-compose run --rm gitlab-runner register  --url http://gitlab.local  --token TOKEN_DUOC_TAO_RA

Đến đây là đã thành công đăng ký gitlab-runner

Đây là đăng ký Runner ở mức Instance gitlab. Ngoài ra ta có thể đăng ký runner ở mức dự án. Bằng cách, vào Settings -> CI/CD

Chọn mục Runner -> Create project runner

Sau đó làm tương tự như phần tạo runner cho Instance

Khi Runner đã được đăng ký, mỗi khi push code lên repository thì ci sẽ chạy qua các lệnh được viết trong file .gitlab-ci.yml

#gitlab.local
stages:
  - build
  - deploy

variables:
  # Disable Docker TLS for dind
  DOCKER_TLS_CERTDIR: ""
  DOCKER_HOST: "tcp://docker:2375"    # <- ensure docker client talks to dind service
  DOCKER_BUILDKIT: "1"                # <- use BuildKit for buildx pushes

# Build CoreAPI image using buildx and push to Docker Hub (registry cache enabled)
build_coreapi:
  stage: build
  image: docker:24
  services:
    - name: docker:24-dind
      alias: docker

  variables:
    DOCKER_DRIVER: overlay2
  before_script:
    - echo "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin
    - docker buildx create --use || true
    - docker info | sed -n '1,5p'   # quick sanity check (no secrets printed)
  script:
    - |
      DATE=$(date +%Y%m%d)
      SHA=${CI_COMMIT_SHORT_SHA}
      IMAGE_TAG="$DATE-$SHA"
      REPO="$DOCKER_USERNAME/corejs-coreapi"
      docker buildx build --progress=plain --platform linux/amd64 --push \
        --tag "$REPO:latest" --tag "$REPO:$IMAGE_TAG" \
        --cache-from=type=registry,ref="$REPO:buildcache" \
        --cache-to=type=registry,ref="$REPO:buildcache",mode=max \
        -f CoreAPI/Dockerfile CoreAPI
  rules:
    - if: '$CI_COMMIT_BRANCH == "nodejs"'

# Build Frontend image using buildx and push to Docker Hub (registry cache enabled)
build_frontend:
  stage: build
  image: docker:24
  services:
    - name: docker:24-dind
      alias: docker

  variables:
    DOCKER_DRIVER: overlay2
  before_script:
    - echo "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin
    - docker buildx create --use || true
    - docker info | sed -n '1,5p'
  script:
    - |
      DATE=$(date +%Y%m%d)
      SHA=${CI_COMMIT_SHORT_SHA}
      IMAGE_TAG="$DATE-$SHA"
      REPO="$DOCKER_USERNAME/corejs-frontend"
      docker buildx build --progress=plain --platform linux/amd64 --push \
        --tag "$REPO:latest" --tag "$REPO:$IMAGE_TAG" \
        --cache-from=type=registry,ref="$REPO:buildcache" \
        --cache-to=type=registry,ref="$REPO:buildcache",mode=max \
        --build-arg NODE_ENV=production \
        -f frontend/Dockerfile frontend
  rules:
    - if: '$CI_COMMIT_BRANCH == "nodejs"'

# Deploy to remote server by SSH (uses SSH_PRIVATE_KEY variable)
deploy:
  stage: deploy
  image: alpine:3.18
  before_script:
    - apk add --no-cache openssh-client bash
    - mkdir -p ~/.ssh
    - echo "$SSH_PRIVATE_KEY" > ~/.ssh/id_rsa || true
    - chmod 600 ~/.ssh/id_rsa || true
    - |
      # add known host only for remote SSH deployments
      if [ -n "$SERVER" ] && [ "$SERVER" != "localhost" ] && [ "$SERVER" != "127.0.0.1" ]; then
        if [ -n "$PORT" ]; then
          ssh-keyscan -p $PORT $SERVER >> ~/.ssh/known_hosts
        else
          ssh-keyscan $SERVER >> ~/.ssh/known_hosts
        fi
      fi
  script:
    - DESTINATION_PATH="/home/$USERNAME/deployments/corejs"
    - DATE=$(date +%Y%m%d)
    - SHA=${CI_COMMIT_SHORT_SHA}
    - IMAGE_TAG="$DATE-$SHA"
    - |
      if [ -z "$SERVER" ] || [ "$SERVER" = "localhost" ] || [ "$SERVER" = "127.0.0.1" ]; then
        echo "Running local deploy (no SSH)..."
        mkdir -p "$DESTINATION_PATH"
        cp -r scripts "$DESTINATION_PATH/"
        chmod +x "$DESTINATION_PATH/scripts/deploy.sh"
        DOCKER_USERNAME='${DOCKER_USERNAME}' DOCKER_PASSWORD='${DOCKER_PASSWORD}' IMAGE_TAG='${IMAGE_TAG}' ALLOWED_HOSTS='${ALLOWED_HOSTS}' bash "$DESTINATION_PATH/scripts/deploy.sh"
      else
        echo "Running remote deploy via SSH..."
        ssh -p ${PORT} ${USERNAME}@${SERVER} "mkdir -p $DESTINATION_PATH"
        scp -P ${PORT} scripts/deploy.sh ${USERNAME}@${SERVER}:$DESTINATION_PATH/
        ssh -p ${PORT} ${USERNAME}@${SERVER} "cd $DESTINATION_PATH && \
          DOCKER_USERNAME='${DOCKER_USERNAME}' DOCKER_PASSWORD='${DOCKER_PASSWORD}' IMAGE_TAG='${IMAGE_TAG}' ALLOWED_HOSTS='${ALLOWED_HOSTS}' bash ./deploy.sh"
      fi
  dependencies:
    - build_coreapi
    - build_frontend
  rules:
    - if: '$CI_COMMIT_BRANCH == "nodejs"'

Bước 4. Kiểm tra và sửa lỗi

Vào Build -> Pipeline

Pipeline đang lỗi, cần kiểm tra và sửa lỗi, Bấm vào Failed để kiểm tra

Cả 2 pipeline đang lỗi,

Lỗi này là do trong docker không phân dải được gitlab.local. Sửa file /etc/gitlab-runner/config.toml trong docker gitlab-runner file này được mount ra file /opt/gitlab-runner/config/config.toml

[[runners]]
  name = "gitlab-runer-local"
  url = "http://gitlab.local"
  id = 2
  token = "glrt-Gs66iShXuQI0W0KQjp4j8286MQp0OjEKdToxCw.01.120274ez3"
  token_obtained_at = 2025-10-01T12:46:25Z
  token_expires_at = 0001-01-01T00:00:00Z
  executor = "docker"
  [runners.cache]
    MaxUploadedArchiveSize = 0
    [runners.cache.s3]
    [runners.cache.gcs]
    [runners.cache.azure]
  [runners.docker]
    tls_verify = false
    image = "docker:latest"
    privileged = true
    disable_entrypoint_overwrite = false
    oom_kill_disable = false
    disable_cache = false
    volumes = ["/cache"]
    shm_size = 0
    network_mtu = 0
    network_mode = "gitlab-network"

Sửa file xong thì restart gitlab-runner

docker compose restart gitlab-runner

Bấm vào Retry để chạy lại

Nguyên nhân lỗi là login vào docker hub không được. Ta cần thêm biến môi trường để có đủ thôgn tin

Thêm biến môi trường: Settings -> CI/CD chọn mục Variables

Add variable

Nhập tên biến và giá trị

Add thêm biến DOCKER_USERNAMEDOCKER_PASSWORD
DOCKER_PASSWORD được tạo ra từ Token Generate trên docker hub.
Vào docker hub, Setting -> Personal access tokens -> Generate new token

Nhập tên Access token description -> Chọn Expiratioin Date -> Chọn Access permission (Read, Write, Delete) -> Generate

Copy token và lưu lại (Docker chỉ hiển thi token 1 lần duy nhất)

Nhập token và DOCKER_PASSWORD rồi kiểm tra lại pipeline

Như vậy đã build thành công.

Tag:
Liên hệ