Operations

Tự động hóa triển khai VPS bằng GitOps cho SysAdmin 2026

SSH vào VPS mới rồi gõ lệnh cài từng gói, sửa từng file config là cách làm phổ biến, nhưng đến khi bạn phải quản lý 5, 10 hay 20 máy chủ thì nó vỡ ngay. Bản sửa trên máy này quên đồng bộ máy kia, config sai không biết sửa từ bao giờ, có người vô tình đổi port SSH mà cả team không ai hay. GitOps giải quyết đúng bài toán đó: lấy Git làm nguồn sự thật riêng biệt (single source of truth), mọi thay đổi hạ tầng đều đi qua commit, được review, và một pipeline tự động áp dụng lên VPS. Bài này hướng dẫn bạn dựng một quy trình GitOps thực chiến cho VPS chạy Ubuntu 24.04, dùng Ansible làm công cụ khai báo cấu hình và GitHub Actions làm pipeline, đúng chuẩn sysadmin năm 2026.

Tóm tắt nhanh: bạn sẽ đặt toàn bộ cấu hình máy chủ (gói phần mềm, file config, user, firewall) vào một repo Git. Mỗi lần push lên nhánh chính, GitHub Actions chạy Ansible playbook để áp dụng lên VPS đích. Mọi thay đổi đều có lịch sử, có thể rollback bằng cách revert commit. Quy trình này áp dụng tốt cho cả VPS đơn lẻ lẫn cụm nhiều máy, và không yêu cầu hạ tầng phức tạp như Kubernetes.

Yêu cầu trước khi bắt đầu

  • Một VPS chạy Ubuntu 24.04 LTS, có IP công khai. Nếu bạn chưa có, có thể thuê VPS Linux với quyền root để thao tác đúng chuẩn GitOps.
  • Một tài khoản GitHub (hoặc GitLab) miễn phí để lưu repo và chạy pipeline.
  • Máy tính cá nhân đã cài Git và SSH client.
  • Hiểu cơ bản về SSH, biết dùng systemctl và quen với cú pháp Ansible ở mức cơ bản.

Vì sao sysadmin nên chuyển sang GitOps năm 2026?

Quản lý VPS kiểu truyền thống dựa vào trí nhớ và tài liệu rời rạc. Bạn cài Nginx, mở firewall, tạo user, rồi quên. Tháng sau có máy mới, bạn lại vừa nhớ vừa đoán mà làm lại từ đầu. GitOps thay thế toàn bộ quy trình đó bằng một repo Git có cấu trúc rõ ràng: mỗi dòng trong file inventory là một máy chủ, mỗi playbook là một lớp cấu hình, mỗi commit là một thay đổi có người review.

Lợi ích lớn nhất không phải là tự động hóa, mà là khả năng tái lập (reproducibility). Cùng một repo, bạn có thể dựng lại một VPS y hệt trong 15 phút thay vì nửa ngày. Khi có sự cố, bạn xem lịch sử commit để biết thay đổi nào gây ra, rồi revert đúng commit đó. Với đội nhiều người, không còn cảnh hai người SSH vào cùng lúc sửa trái ngược nhau vì mọi thứ đều đi qua pull request và review.

Năm 2026, công cụ GitOps đã trưởng thành. Ansible vẫn là lựa chọn hợp lý cho VPS đơn lẻ nhờ không cần agent, còn với hạ tầng container, Argo CD và Flux đã trở thành chuẩn. Bài này tập trung vào Ansible vì nó bao phủ tốt cả hai mảng: cấu hình OS và triển khai ứng dụng.

Bước 1 - Khởi tạo repo Git và cấu trúc thư mục

Trên máy tính cá nhân, tạo repo mới và cấu trúc thư mục chuẩn Ansible. Cấu trúc này tách biệt phần khai báo máy chủ (inventory) với phần định nghĩa cấu hình (playbook, role).

mkdir vps-gitops && cd vps-gitops
git init
mkdir -p inventory playbooks roles/nginx files templates

Tiếp theo, tạo file inventory khai báo VPS của bạn. Thay YOUR_VPS_IP bằng IP thật và deploy bằng user bạn sẽ dùng để chạy Ansible.

# file: inventory/production.ini
[webservers]
vps1 ansible_host=YOUR_VPS_IP ansible_user=deploy ansible_ssh_private_key_file=~/.ssh/id_ed25519

Lưu ý: không nên dùng user root trực tiếp. Tạo một user deploy có quyền sudo trên VPS trước, rồi dùng user đó cho Ansible. Đây là thói quen bảo mật nên giữ từ đầu.

Bước 2 - Viết playbook khai báo cấu hình cơ bản

Playbook đầu tiên sẽ đảm bảo VPS luôn ở trạng thái mong muốn: hệ thống được cập nhật, Nginx được cài, firewall bật đúng port, user deploy có SSH key. Tạo file playbooks/setup.yml:

---
- hosts: webservers
  become: true
  vars:
    - ssh_port: 22
  tasks:
    - name: Cập nhật cache apt
      apt:
        update_cache: true
        cache_valid_time: 3600

    - name: Cài đặt các gói cần thiết
      apt:
        name:
          - nginx
          - ufw
          - fail2ban
        state: present

    - name: Bật UFW và cho phép SSH
      ufw:
        rule: allow
        port: "{{ ssh_port }}"
        proto: tcp

    - name: Bật UFW
      ufw:
        state: enabled
        policy: deny

Playbook này mô tả trạng thái cuối cùng mong muốn của VPS, chứ không phải chuỗi lệnh để đạt được nó. Đó là tư duy cốt lõi của GitOps: bạn khai báo "cái gì", Ansible lo "làm thế nào". Kiểm tra cú pháp trước khi chạy:

ansible-playbook -i inventory/production.ini playbooks/setup.yml --check

Cờ --check chạy ở chế độ mô phỏng, chỉ báo cáo những gì sẽ thay đổi mà không áp dụng. Output mong đợi là danh sách các task ở trạng thái changed hoặc ok, kèm dòng "PLAY RECAP" ở cuối. Nếu có lỗi cú pháp, Ansible sẽ báo ngay từ bước parse.

Bước 3 - Tổ chức cấu hình bằng roles và templates

Khi playbook dài dần, bạn nên nhóm các tác vụ liên quan thành role. Role nginx sẽ quản lý toàn bộ cấu hình web server. Tạo cấu trúc role:

mkdir -p roles/nginx/{tasks,templates,handlers}

File roles/nginx/tasks/main.yml định nghĩa các task cài đặt và bật Nginx:

---
- name: Cài đặt Nginx
  apt:
    name: nginx
    state: present

- name: Copy cấu hình site mặc định
  template:
    src: default.conf.j2
    dest: /etc/nginx/sites-available/default
  notify: reload nginx

- name: Bật và khởi động Nginx
  systemd:
    name: nginx
    state: started
    enabled: true

File roles/nginx/templates/default.conf.j2 là template Jinja2, cho phép chèn biến từ Ansible:

server {
    listen 80 default_server;
    server_name {{ domain_name }};

    root /var/www/html;
    index index.html;

    location / {
        try_files $uri $uri/ =404;
    }
}

File roles/nginx/handlers/main.yml định nghĩa hành động reload khi config thay đổi:

---
- name: reload nginx
  systemd:
    name: nginx
    state: reloaded

Khi đó, playbook chính chỉ còn vài dòng gọi role:

---
- hosts: webservers
  become: true
  vars:
    domain_name: example.com
  roles:
    - nginx

Cách tổ chức này giúp bạn tái sử dụng role cho nhiều VPS khác nhau, chỉ cần thay đổi biến domain_name trong inventory hoặc file vars riêng.

Bước 4 - Thiết lập GitHub Actions để tự động áp dụng thay đổi

Đây là bước biến repo Git thành pipeline thực thụ. Mỗi lần bạn push commit lên nhánh main, GitHub Actions sẽ tự động chạy Ansible để áp dụng cấu hình mới lên VPS. Tạo file .github/workflows/deploy.yml:

name: Deploy VPS via Ansible

on:
  push:
    branches: [ main ]

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Cài đặt Ansible
        run: |
          sudo apt update
          sudo apt install -y ansible

      - name: Tạo SSH key từ secret
        run: |
          mkdir -p ~/.ssh
          echo "${{ secrets.DEPLOY_SSH_KEY }}" > ~/.ssh/id_ed25519
          chmod 600 ~/.ssh/id_ed25519
          ssh-keyscan -H YOUR_VPS_IP >> ~/.ssh/known_hosts

      - name: Chạy Ansible playbook
        run: |
          ansible-playbook -i inventory/production.ini playbooks/setup.yml

Để pipeline hoạt động, bạn cần thêm SSH private key của user deploy vào GitHub Secrets với tên DEPLOY_SSH_KEY. Vào Settings của repo, chọn Secrets and variables, Actions, rồi New repository secret.

Bây giờ quy trình làm việc là: sửa file config trong repo, commit, push. GitHub Actions lo phần còn lại. Verify bằng cách vào tab Actions trên GitHub, xem workflow chạy thành công với trạng thái màu xanh, rồi SSH vào VPS kiểm tra:

systemctl status nginx

Output mong đợi: active (running). Nếu bạn sửa template default.conf.j2 và push, handler sẽ tự động reload Nginx mà không cần chạm tay vào máy chủ.

Bước 5 - Quản lý secrets và biến môi trường an toàn

hiếm khi commit file chứa mật khẩu, API key hay private key vào repo, kể cả repo riêng tư. Thay vào đó, dùng Ansible Vault để mã hóa các biến nhạy cảm ngay trong repo, hoặc lưu trên GitHub Secrets cho pipeline.

Để mã hóa một file biến:

ansible-vault encrypt vars/secrets.yml

Khi tạo file mới:

ansible-vault create vars/secrets.yml

Lệnh này mở editor và tự động mã hóa file sau khi lưu. Khi chạy playbook có dùng file vault, thêm cờ --ask-vault-pass:

ansible-playbook -i inventory/production.ini playbooks/setup.yml --ask-vault-pass

Với GitHub Actions, truyền mật khẩu vault qua secret và chạy:

echo "${{ secrets.VAULT_PASS }}" > vault_pass.txt
ansible-playbook -i inventory/production.ini playbooks/setup.yml --vault-password-file vault_pass.txt

File vault_pass.txt chỉ tồn tại trong lúc chạy, sau đó bị xóa khi job kết thúc. Nguyên tắc chung: cấu hình không nhạy cảm để trong Git, dữ liệu nhạy cảm mã hóa bằng Vault hoặc giữ ngoài repo.

Bước 6 - Rollback khi có sự cố

Lợi thế lớn nhất của GitOps là rollback nhanh và an toàn. Khi một commit mới gây lỗi (ví dụ Nginx không khởi động được vì config sai), bạn chỉ cần revert commit đó rồi push lại.

git log --oneline -5
git revert HEAD

Sau khi push, pipeline tự động chạy và đưa VPS về trạng thái trước đó. Nếu muốn kiểm tra trước khi áp dụng, bạn có thể thêm bước kiểm tra cú pháp ngay trong pipeline:

ansible-playbook -i inventory/production.ini playbooks/setup.yml --syntax-check

Kỹ thuật nâng cao hơn là kiểm tra thực tế trước khi áp dụng lên production. Bạn có thể tạo một VPS staging riêng bằng cách thêm vào inventory với biến ansible_host khác, chạy pipeline trên staging trước, rồi mới merge vào nhánh main để deploy production.

Xử lý lỗi thường gặp khi chạy Ansible qua GitOps

Lỗi "Permission denied" khi SSH từ GitHub Actions

Pipeline không SSH được vào VPS. Kiểm tra: user deploy có tồn tại không, public key đã được thêm vào ~/.ssh/authorized_keys của user đó chưa, và GitHub Secret DEPLOY_SSH_KEY có đúng private key không. Chạy thử thủ công từ máy tính:

ssh deploy@YOUR_VPS_IP

Nếu SSH từ máy thường hoạt động nhưng từ Actions không được, kiểm tra lại định dạng key trong Secret, đảm bảo có dòng -----BEGIN OPENSSH PRIVATE KEY----- ở đầu.

Ansible báo "Timeout (12s)" khi kết nối

Thường do firewall trên VPS chặn port SSH hoặc IP của GitHub Actions không được phép. Kiểm tra UFW trên VPS có cho phép SSH từ mọi nơi không, hoặc thêm IP range của GitHub Actions vào whitelist. Log chi tiết hơn bằng cờ -vvv:

ansible-playbook -i inventory/production.ini playbooks/setup.yml -vvv

Thay đổi trên Git không được áp dụng lên VPS

Pipeline chạy thành công nhưng config trên máy chủ không đổi. Nguyên nhân hay gặp nhất là do bạn đang chỉnh sửa một file không có trong task Ansible, hoặc handler không được kích hoạt vì template không thay đổi. Kiểm tra bằng cách chạy playbook ở chế độ verbose để xem từng task:

ansible-playbook -i inventory/production.ini playbooks/setup.yml -v

Nếu task copy cấu hình site báo ok thay vì changed, nghĩa là nội dung file giống hệt bản hiện tại, Ansible không cần reload. Điều này đúng, không phải lỗi.

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

GitOps có áp dụng được cho VPS Windows Server không?

Được. Ansible hỗ trợ Windows qua WinRM, bạn khai báo ansible_connection: winrm trong inventory và viết playbook bằng các module win_*. Cấu trúc repo và quy trình pipeline hoàn toàn giống nhau.

Có cần dùng Kubernetes mới làm GitOps được không?

Không. Kubernetes và Argo CD là một nhánh của GitOps dành cho hạ tầng container. Với VPS truyền thống, Ansible + Git + CI/CD pipeline là đủ và đơn giản hơn nhiều. Nguyên tắc cốt lõi vẫn là Git làm nguồn sự thật.

Một repo GitOps nên quản lý bao nhiêu VPS?

Không có giới hạn cứng. Bạn có thể nhóm VPS theo môi trường (staging, production) hoặc theo vai trò (web, database, CI) trong cùng một inventory. Repo càng lớn thì thời gian chạy pipeline càng lâu, nên khi vượt vài chục server, bạn nên tách thành nhiều repo theo nhóm dịch vụ.

Làm sao để kiểm tra thay đổi trước khi áp dụng lên VPS thật?

Dùng chế độ --check của Ansible để mô phỏng, hoặc thiết lập một VPS staging riêng trong inventory. Pipeline có thể deploy lên staging trước, chạy kiểm tra tự động, rồi mới merge sang nhánh production.

GitOps có giúp giảm chi phí thuê VPS không?

Gián tiếp là có. Khi mọi cấu hình nằm trong Git, bạn có thể tắt VPS không dùng và dựng lại bất kỳ lúc nào mà không sợ mất cấu hình. Điều này giúp bạn chủ động thuê VPS giá rẻ cho môi trường staging rồi tắt đi khi không cần, thay vì giữ máy chạy phí tiền hàng tháng.

Bài viết liên quan

Lưu ý: Bài viết mang tính tham khảo, tổng hợp kiến thức chung. Mỗi hệ thống, hạ tầng và nhu cầu có đặc thù riêng, nên kiểm thử trong môi trường an toàn và tham vấn kỹ sư trước khi triển khai thực tế.