Cài đặt GitLab Runner trên VPS Ubuntu: Tự động hóa CI/CD (2026)

Tác giả: Trần Thảo 08 tháng 02, 2026

Trong quy trình phát triển phần mềm chuyên nghiệp, việc triển khai mã nguồn (deploy code) thủ công là một “điểm nghẽn” kỹ thuật nghiêm trọng. Thói quen SSH vào máy chủ, gõ lệnh git pull, cài đặt thư viện và khởi động lại dịch vụ bằng tay không chỉ tiêu tốn hàng giờ đồng hồ quý báu mà còn tiềm ẩn rủi ro sai sót rất cao. Chỉ một câu lệnh gõ nhầm cũng có thể khiến hệ thống production ngừng hoạt động.

Giải pháp triệt để cho vấn đề này là áp dụng quy trình CI/CD (Continuous Integration / Continuous Deployment). Để hiện thực hóa điều đó, bước quan trọng nhất chính là Cài đặt GitLab Runner trên VPS của riêng bạn. Nếu bạn chưa có máy chủ, hãy tìm hiểu xem Cloud VPS là gì? So sánh ưu điểm của Cloud VPS và VPS vật lý thông thường để lựa chọn hạ tầng phù hợp nhất cho hệ thống CI/CD.

Bài viết này là tài liệu hướng dẫn kỹ thuật chuyên sâu, giúp bạn thiết lập một hệ thống GitLab Runner mạnh mẽ trên nền tảng Ubuntu (22.04/24.04). Chúng ta sẽ sử dụng kiến trúc Docker Executor kết hợp với quy trình xác thực Authentication Token hiện đại nhất để đảm bảo hệ thống vừa vận hành tốc độ cao, vừa tuân thủ các chuẩn mực bảo mật khắt khe.

Tổng quan: Tại sao chọn Docker Executor cho VPS?

Minh họa quy trình tự động hóa DevOps

Trước khi đi vào cài đặt, chúng ta cần xác định rõ kiến trúc hệ thống sẽ xây dựng. Khi cài đặt GitLab Runner trên VPS, bạn có hai lựa chọn chính về môi trường thực thi (Executor): Shell và Docker.

Với Shell Executor, Runner sẽ thực thi các câu lệnh trực tiếp trên hệ điều hành của VPS. Phương pháp này tuy đơn giản nhưng lại tạo ra một môi trường thiếu tính biệt lập. Các thư viện, file tạm và cấu hình của dự án sẽ nằm rải rác trên server, dễ gây xung đột phiên bản (Dependency Hell) khi bạn chạy nhiều dự án khác nhau trên cùng một máy chủ.

Ngược lại, Docker Executor là tiêu chuẩn vàng trong DevOps hiện đại. Runner sẽ khởi tạo một container hoàn toàn mới và biệt lập cho mỗi lần chạy pipeline (build job). Sau khi công việc hoàn tất, container này sẽ được hủy bỏ.

  • Tính nhất quán: Môi trường build luôn giống nhau 100% ở mọi lần chạy.
  • Sự an toàn: Code của bạn chạy trong container, không ảnh hưởng trực tiếp đến hệ điều hành của VPS.
  • Linh hoạt: Dễ dàng build dự án Node.js, sau đó chuyển sang build dự án Python trên cùng một Runner mà không cần cài đặt môi trường phức tạp lên VPS.

Dưới đây là bảng so sánh chi tiết giữa hai loại Executor phổ biến nhất trên VPS:

Tiêu chí Shell Executor Docker Executor (Khuyên dùng)
Cơ chế hoạt động Chạy lệnh trực tiếp trên hệ điều hành VPS (Host OS). Chạy lệnh trong các Container biệt lập, sinh ra và hủy đi theo từng Job.
Môi trường (Isolation) Thấp. Dùng chung tài nguyên và thư viện với VPS. Dễ gây xung đột (Dependency Hell). Cao. Mỗi Job có môi trường sạch sẽ 100%, không ảnh hưởng lẫn nhau.
Bảo mật Rủi ro. Lệnh chạy có thể can thiệp trực tiếp vào file hệ thống của VPS. An toàn. Code chạy trong sandbox (Container), hạn chế rủi ro cho VPS gốc.
Độ phức tạp Dễ cài đặt, không cần kiến thức Docker. Cần kiến thức Docker cơ bản và cấu hình quyền hạn (Privileged).
Phù hợp nhất Các tác vụ quản trị hệ thống đơn giản, chạy script shell. Build ứng dụng (Node, PHP, Go…), chạy Test, quy trình CI/CD chuẩn.

Dựa trên bảng so sánh trên, chúng ta sẽ triển khai theo mô hình Docker Executor để đảm bảo tính chuyên nghiệp và khả năng mở rộng lâu dài.

Chuẩn bị tài nguyên và môi trường VPS

Minh họa đóng gói phần mềm Docker

Để hệ thống CI/CD hoạt động mượt mà, đặc biệt là khi thực hiện các tác vụ nặng như build Docker Image, VPS cần đáp ứng một số yêu cầu phần cứng nhất định.

Cấu hình khuyến nghị:

  • Hệ điều hành: Ubuntu 22.04 LTS hoặc 24.04 LTS.
  • CPU: Tối thiểu 2 Core.
  • RAM: Tối thiểu 4GB. (Quá trình build Docker, ví dụ npm install hoặc docker build, thường tiêu tốn nhiều RAM. Nếu RAM thấp hơn, bạn cần thiết lập SWAP file để tránh lỗi Out of Memory).
  • Quyền hạn: Truy cập SSH với quyền root hoặc người dùng có quyền sudo.

Thiết lập Docker Engine (Chuẩn bảo mật Keyrings)

VPS bắt buộc phải có Docker Engine để Docker Executor hoạt động. Chúng ta sẽ cài đặt Docker theo phương pháp sử dụng thư mục /etc/apt/keyrings, đây là chuẩn bảo mật mới nhất thay thế cho phương pháp apt-key cũ đã lỗi thời.

Mẹo: Sau khi cài đặt xong Docker, bạn có thể tham khảo thêm cách Cài đặt Portainer trên VPS Linux: Quản lý Docker & Kubernetes giao diện web để quản lý các container trực quan hơn thay vì dùng dòng lệnh.

Bước 1: Cập nhật hệ thống và cài đặt gói phụ trợ

Đầu tiên, hãy đảm bảo hệ thống của bạn đã được cập nhật và có đủ các công cụ cần thiết để tải gói qua HTTPS.

Cập nhật danh sách gói:

sudo apt-get update

Cài đặt các gói phụ thuộc cần thiết:

sudo apt-get install ca-certificates curl gnupg

Bước 2: Thiết lập GPG Key cho Docker

Chúng ta sẽ tạo thư mục chứa khóa an toàn và tải khóa GPG chính thức từ Docker. Việc này đảm bảo các gói phần mềm bạn cài đặt là chính hãng và không bị giả mạo.

Tạo thư mục keyrings:

sudo install -m 0755 -d /etc/apt/keyrings

Tải và cấu hình khóa GPG:

curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg

Phân quyền đọc cho khóa:

sudo chmod a+r /etc/apt/keyrings/docker.gpg

Bước 3: Thêm Repository Docker vào nguồn APT

Lệnh dưới đây sẽ tự động phát hiện phiên bản Ubuntu của bạn và thêm kho lưu trữ tương ứng vào danh sách nguồn.

echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
  $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
  sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

Bước 4: Cài đặt Docker Engine

Tiến hành cập nhật lại chỉ mục gói và cài đặt bộ công cụ Docker toàn diện.

Cập nhật lại index:

sudo apt-get update

Cài đặt Docker và các plugin liên quan:

sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin -y

Bước 5: Kiểm tra hoạt động

sudo docker --version

Nếu hệ thống trả về thông tin phiên bản (ví dụ: Docker version 27.x.x), bạn đã hoàn tất bước chuẩn bị môi trường.

Cài đặt GitLab Runner trên VPS

Tiếp theo, chúng ta sẽ cài đặt phần mềm GitLab Runner. Chúng ta sẽ sử dụng kho lưu trữ chính thức của GitLab để đảm bảo tính ổn định và khả năng cập nhật lâu dài.

Bước 1: Thêm Repository của GitLab Runner

curl -L "https://packages.gitlab.com/install/repositories/runner/gitlab-runner/script.deb.sh" | sudo bash

Bước 2: Cài đặt gói phần mềm

sudo apt install gitlab-runner -y

Bước 3: Xác nhận trạng thái dịch vụ

sudo gitlab-runner status

Kết quả mong đợi là Service is running. Lúc này, Runner đã được cài đặt nhưng chưa được liên kết với bất kỳ dự án nào.

Kết nối Runner với GitLab (Quy trình Authentication Token)

Đây là bước cốt lõi để “giới thiệu” VPS của bạn với GitLab Server. Chúng ta sẽ sử dụng quy trình Authentication Token, phương pháp định danh hiện đại giúp quản lý cấu hình tập trung và bảo mật hơn so với Registration Token cũ.

Bước 1: Khởi tạo Runner trên giao diện GitLab (UI)

Tất cả các siêu dữ liệu (metadata) như Tags, Mô tả, Cấu hình bảo vệ (Protected) đều phải được định nghĩa trên giao diện web trước khi chạy lệnh trên VPS.

  1. Truy cập vào Project (hoặc Group) của bạn trên GitLab.
  2. Điều hướng đến menu Settings > CI/CD.
  3. Mở rộng phần Runners và chọn nút New project runner.
  4. Điền các thông tin cấu hình quan trọng:
    • Tags: Nhập các từ khóa định danh như docker, vps, production. (Lưu ý: Bạn bắt buộc phải nhập Tag ở bước này để phân loại Runner).
    • Run untagged jobs: Tích chọn nếu bạn muốn Runner này xử lý cả những job không có tag cụ thể.
    • Description: Nhập mô tả gợi nhớ, ví dụ: VPS-Ubuntu-22.04-Docker-Executor.
  5. Nhấn nút Create runner.
  6. Hệ thống sẽ hiển thị một mã token bắt đầu bằng glrt-. Hãy Copy mã này ngay lập tức vì bạn sẽ dùng nó ở bước tiếp theo.

Bước 2: Kích hoạt Runner trên VPS

Quay trở lại cửa sổ terminal của VPS, bạn sẽ thực hiện lệnh đăng ký. Vì toàn bộ cấu hình đã được khai báo trên Web, câu lệnh tại VPS trở nên rất gọn nhẹ và chỉ tập trung vào việc xác định môi trường thực thi.

Hãy thay thế glrt-YOUR_TOKEN_HERE bằng mã token bạn vừa copy:

sudo gitlab-runner register \
  --non-interactive \
  --url "https://gitlab.com/" \
  --token "glrt-YOUR_TOKEN_HERE" \
  --executor "docker" \
  --docker-image "docker:stable"

Khi lệnh chạy xong và không báo lỗi, kết nối giữa VPS và GitLab đã được thiết lập thành công.

Cấu hình chuyên sâu: Privileged Mode và tối ưu hóa

Bảo mật trong Cloud Computing

Mặc dù Runner đã hoạt động, nhưng cấu hình mặc định chưa đủ để thực hiện các tác vụ nâng cao như Docker-in-Docker (DinD) – kỹ thuật cho phép bạn chạy lệnh docker build ngay bên trong một container Docker khác. Để làm được điều này, chúng ta cần can thiệp vào file cấu hình config.toml.

Truy cập file cấu hình:

sudo nano /etc/gitlab-runner/config.toml

Bạn cần tìm đến block [runners.docker] tương ứng với runner vừa tạo và thực hiện các điều chỉnh sau:

Kích hoạt Privileged Mode (bắt buộc cho DinD)

Tìm dòng privileged và đổi giá trị từ false sang true.

privileged = true

Lưu ý quan trọng: Thiết lập privileged = true cấp quyền truy cập mở rộng cho container vào thiết bị của máy chủ (Host). Đây là yêu cầu kỹ thuật bắt buộc để daemon Docker bên trong container có thể hoạt động. Hãy đảm bảo bạn chỉ chạy các pipeline từ nguồn mã nguồn tin cậy để kiểm soát rủi ro bảo mật.

Tối ưu hóa Cache với Pull Policy

Để tăng tốc độ build và tiết kiệm băng thông mạng, hãy thêm cấu hình pull_policy.

pull_policy = ["if-not-present"]

Cấu hình này chỉ đạo Runner kiểm tra xem Docker Image đã có sẵn trên VPS chưa. Nếu có rồi, nó sẽ sử dụng ngay lập tức thay vì tải lại từ Internet mỗi lần chạy job.

File cấu hình hoàn chỉnh sẽ trông giống như sau:

[[runners]]
  name = "VPS-Ubuntu-22.04-Docker-Executor"
  url = "https://gitlab.com/"
  token = "glrt-xxxxxxxxxxxxxx"
  executor = "docker"
  [runners.docker]
    tls_verify = false
    image = "docker:stable"
    privileged = true
    disable_entrypoint_overwrite = false
    oom_kill_disable = false
    disable_cache = false
    volumes = ["/cache"]
    shm_size = 0
    pull_policy = ["if-not-present"]

Sau khi lưu file (Ctrl+O -> Enter -> Ctrl+X), hãy khởi động lại dịch vụ để áp dụng thay đổi:

sudo gitlab-runner restart

Triển khai pipeline CI/CD thực tế

Bây giờ hệ thống đã sẵn sàng, chúng ta sẽ thiết lập một quy trình CI/CD hoàn chỉnh. Kịch bản phổ biến nhất là: Đóng gói ứng dụng thành Docker Image -> Đẩy lên Registry -> SSH vào VPS để Deploy.

Thiết lập biến môi trường (Variables)

Để bảo mật thông tin đăng nhập và khóa SSH, bạn không nên viết trực tiếp vào file code. Hãy vào Settings > CI/CD > Variables trên GitLab và thêm biến:

  • SSH_PRIVATE_KEY: Nội dung file khóa riêng tư (Private Key) dùng để SSH vào VPS.

File cấu hình .gitlab-ci.yml

Tạo file này tại thư mục gốc của dự án với nội dung sau. Lưu ý cấu hình DOCKER_TLS_CERTDIR để xử lý vấn đề kết nối TLS của Docker.

image: docker:stable

# Định nghĩa các biến toàn cục
variables:
  # Tắt TLS cho Docker-in-Docker để tránh lỗi kết nối (Cannot connect to Docker daemon)
  DOCKER_TLS_CERTDIR: ""
  IMAGE_TAG: $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA

# Kích hoạt service Docker-in-Docker
services:
  - docker:dind

stages:
  - build
  - deploy

# Stage 1: Build và Push Docker Image
build_image:
  stage: build
  script:
    - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
    - docker build -t $IMAGE_TAG .
    - docker push $IMAGE_TAG
  tags:
    - docker # Tag này phải khớp với tag bạn đã tạo trên UI

# Stage 2: SSH vào VPS và Deploy
deploy_to_vps:
  stage: deploy
  image: alpine:latest
  script:
    # Cài đặt SSH Client
    - apk add --no-cache openssh-client
    - eval $(ssh-agent -s)
    
    # Nạp Private Key vào Agent
    - echo "$SSH_PRIVATE_KEY" | tr -d '\r' | ssh-add -
    
    # Tạo thư mục SSH và thêm VPS vào Known Hosts
    - mkdir -p ~/.ssh
    - chmod 700 ~/.ssh
    - ssh-keyscan YOUR_VPS_IP >> ~/.ssh/known_hosts
    
    # Thực thi lệnh Deploy trên VPS
    - ssh root@YOUR_VPS_IP "docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY && docker pull $IMAGE_TAG && docker stop my-app || true && docker rm my-app || true && docker run -d --name my-app -p 80:80 $IMAGE_TAG"
  tags:
    - docker
  only:
    - main

Khắc phục sự cố thường gặp (Troubleshooting)

Trong quá trình vận hành, bạn có thể gặp phải một số vấn đề kỹ thuật. Dưới đây là cách xử lý các lỗi phổ biến nhất.

Lỗi 1: “Cannot connect to the Docker daemon at tcp://docker:2375”

Đây là lỗi kinh điển khi sử dụng Docker-in-Docker. Nguyên nhân là do Docker daemon mặc định yêu cầu kết nối bảo mật qua TLS, trong khi client lại cố kết nối qua cổng không bảo mật.

  • Giải pháp: Đảm bảo bạn đã khai báo biến DOCKER_TLS_CERTDIR: "" trong file .gitlab-ci.yml. Giá trị rỗng này sẽ tắt yêu cầu TLS, cho phép các container giao tiếp qua cổng 2375.

Lỗi 2: Runner không nhận Job (Stuck status)

  • Giải pháp: Kiểm tra lại phần Tags của Runner trên GitLab và tags trong file .gitlab-ci.yml. Hai giá trị này phải khớp nhau hoàn toàn. Nếu Job của bạn không có tag, hãy đảm bảo bạn đã tích chọn “Run untagged jobs” trong phần cài đặt Runner.

Lỗi 3: VPS bị đầy ổ cứng (Disk Usage)

Docker tạo ra rất nhiều layer ảnh (dangling images) và container rác sau mỗi lần build. Nếu không dọn dẹp, ổ cứng VPS sẽ nhanh chóng bị đầy.

  • Giải pháp: Thiết lập một Cronjob trên VPS để tự động dọn dẹp hệ thống mỗi ngày. Chạy lệnh crontab -e và thêm dòng sau để dọn dẹp vào lúc 3 giờ sáng:
0 3 * * * docker system prune -af --volumes

Câu hỏi thường gặp (FAQ)

1. Tại sao lệnh register không nhận tham số --tag-list hay --description?

Do bạn đang dùng Token xác thực mới (glrt-). Toàn bộ cấu hình Metadata này bắt buộc phải thực hiện trên giao diện Web GitLab trước khi lấy Token.

2. Tại sao Job báo lỗi “Cannot connect to the Docker daemon”?

Do Docker mặc định bật TLS mà DinD chưa cấu hình certificate. Cách xử lý nhanh nhất: Thêm biến DOCKER_TLS_CERTDIR: "" vào file .gitlab-ci.yml.

3. Tại sao bắt buộc phải bật privileged = true?

Để chạy được “Docker trong Docker” (Docker-in-Docker). Nếu không bật, container Runner không có quyền truy cập vào thiết bị để tạo container con.

4. Ổ cứng VPS bị đầy sau một thời gian chạy CI/CD?

Docker sinh ra nhiều file rác. Hãy cài đặt Cronjob chạy lệnh docker system prune -af --volumes định kỳ mỗi ngày để dọn dẹp.

5. Tôi có thể chạy nhiều Job cùng lúc trên 1 VPS không?

Có. Hãy sửa tham số concurrent trong file /etc/gitlab-runner/config.toml lên số lượng bạn muốn (ví dụ: concurrent = 4).

Kết luận

Việc cài đặt GitLab Runner trên VPS là một khoản đầu tư xứng đáng về mặt kỹ thuật cho bất kỳ đội ngũ phát triển nào. Nó trao cho bạn quyền kiểm soát hoàn toàn hạ tầng CI/CD, đảm bảo tính bảo mật cho mã nguồn và tăng tốc độ triển khai sản phẩm đáng kể.

Với hướng dẫn chi tiết trên, bạn đã sở hữu một hệ thống Automation DevOps chuẩn mực: từ việc thiết lập Docker an toàn, quy trình xác thực Token hiện đại, cho đến khả năng xử lý Docker-in-Docker mạnh mẽ. Hãy bắt đầu tích hợp pipeline ngay hôm nay để giải phóng bản thân khỏi những thao tác thủ công nhàm chán.

Ngoài ra, để hoàn thiện môi trường làm việc từ xa, bạn có thể kết hợp Cài đặt VS Code Server trên VPS: Biến trình duyệt thành Cloud IDE mạnh mẽ để code và deploy trực tiếp trên cùng một hạ tầng.

Tài liệu tham khảo