Sau khi cài Debian mới, tôi thường có một số packages cài lại mỗi lần. Thay vì cài thủ công từng gói một, tôi giữ chúng trong một script Bash đơn giản và cài tất cả bằng một command duy nhất.

Với tôi, đây là giải pháp nhẹ và hiệu quả fi cho việc cài gói cơ bản. Không cần dùng đến một nền tảng tự động hóa chỉ để cài một danh sách packages.

Cụ thể, đây là những gì tôi làm sau khi cài Debian:

  • Chạy một script Bash hậu cài đặt đơn giản,
  • Cài tất cả packages cần thiết.

Script của tôi khá tối giản và chứa hai loại packages:

  • Công cụ cơ bản hữu ích trên gần như mọi máy để bàn
  • Các packages riêng cho máy để bàn mà tôi đặc biệt muốn

Nếu sau này thiết lập vượt ra ngoài việc cài gói và chuyển sang cấu hình hệ thống, tôi sẽ chuyển sang Ansible.

Xin lưu ý rằng hướng dẫn này đặc biệt là một hướng dẫn hậu cài đặt -i tập trung vào gói, không phải hướng dẫn hậu cài đặt Debian hay Ubuntu đầy đủ/tổng quát. Nếu bạn muốn một hướng dẫn hậu cài đặt thiết yếu đầy đủ, hãy xem các liên kết sau:

1. Tạo script Bash hậu cài đặt đơn giản cho Debian / Ubuntu

Giữ tất cả script trong một thư mục sẽ tiện hơn. Vậy để tôi tạo thư mục scripts:

mkdir -p ~/scripts

Tạo script:

nano ~/scripts/install-deb-essential-packages.sh

Thêm nội dung:

#!/usr/bin/env bash
set -euo pipefail
PACKAGES=(
# Basic tools
git
curl
wget
ca-certificates
unzip
build-essential
# Personal desktop packages
firmware-cirrus
papirus-icon-theme
timeshift
gnome-shell-extension-manager
vim
gnome-shell-extension-dashtodock
gnome-themes-extra
flatpak
gnome-software-plugin-flatpak
steam-installer
)
echo "Updating package lists..."
sudo apt update
echo "Installing packages..."
sudo apt install -y "${PACKAGES[@]}"
echo "Done."

Xin lưu ý rằng một số packages chỉ có trên một nền tảng cụ thể. Vì vậy bạn có thể cần sửa script này và thêm hoặc bớt packages tùy theo bản phân phối Linux của mình. Sau khi đã thêm tất cả packages thiết yếu cần cài, hãy lưu script và đóng lại.

Cấp quyền thực thi:

chmod +x ~/scripts/install-deb-essential-packages.sh

Chạy script để cài tất cả packages thiết yếu cùng lúc trên hệ thống Debian/Ubuntu của bạn:

~/scripts/install-deb-essential-packages.sh

Bạn có thể dùng cùng script này cho các hệ thống dựa trên Debian khác như Ubuntu và các bản phái sinh của Ubuntu như Linux Mint, Pop!_OS, ElementaryOS và Zorin OS.

Như đã nói, một số packages có thể chỉ có trên một phiên bản cụ thể. Hãy chắc chắn rằng các packages trong script có sẵn cho bản phân phối Linux của bạn. Bạn có thể kiểm tra tính khả dụng của gói như mô tả trong liên kết dưới đây:

2. Vì sao chọn những gói cơ bản này?

Nhóm đầu tiên được cố ý giữ nhỏ.

git

Hữu ích để clone kho mã nguồn và quản lý các file cấu hình.

git clone ...

curl

Công cụ dòng lệnh đa dụng -p để truyền dữ liệu qua các giao thức mạng. Nhiều hướng dẫn cài đặt và script dùng nó.

wget

Một trình tải xuống dòng lệnh hữu ích khác.

ca-certificates

Cung cấp chứng chỉ CA tin cậy cho các kết nối HTTPS/TLS của phần mềm.

unzip

Hữu ích vì phần mềm và dự án tải về thường ở dạng lưu trữ .zip.

build-essential

Cung cấp bộ công cụ biên dịch cơ bản tiêu chuẩn, gồm các công cụ như gcc và make. Debian đặc biệt xác định đây là gói then chốt cho một môi trường build cơ bản.

build-essential không thực sự cần thiết cho mọi người dùng máy để bàn. Nếu biết mình sẽ không biên dịch phần mềm, tôi có thể bỏ nó. Nó được đưa vào đây vì là nền tảng hữu ích cho một máy cá nhân hướng phát triển.

3. Vì sao dùng mảng Bash?

Thay vì chạy thủ công:

sudo apt install git
sudo apt install curl
sudo apt install wget
sudo apt install unzip

Tôi duy trì một danh sách:

PACKAGES=(
git
curl
wget
unzip
)

Rồi cài tất cả bằng:

sudo apt install -y "${PACKAGES[@]}"

Cách này:

  • Nhanh hơn
  • Dễ bảo trì hơn
  • Dễ sửa
  • Dễ tái sử dụng sau khi cài lại Debian

Thêm một gói chỉ đơn giản là thêm một dòng:

PACKAGES=(
git
curl
wget
neovim
)

4. Vì sao dùng set -euo pipefail?

Như bạn có thể nhận thấy, script bắt đầu bằng:

set -euo pipefail

Điều này khiến script an toàn hơn.

Cụ thể, -e khiến script dừng lại khi một command thất bại thay vì tiếp tục một cách mù quáng.

Với một script thiết lập cá nhân nhỏ, đây là mặc định tốt.

5. Tách riêng các gói cá nhân

Khi danh sách lớn dần, sẽ hữu ích nếu phân biệt giữa công cụ đa dụng và những thứ đặc thù cho thiết lập của tôi.

Ví dụ:

PACKAGES=(
# Basic tools
git
curl
wget
ca-certificates
unzip
build-essential
# Desktop
firmware-cirrus
papirus-icon-theme
gnome-shell-extension-manager
gnome-shell-extension-dashtodock
gnome-themes-extra
# Applications
timeshift
flatpak
gnome-software-plugin-flatpak
steam-installer
# Editor
vim
)

Điều này giúp script dễ hiểu hơn về sau.

6. Khi nào tôi dùng Ansible?

Một số bạn thắc mắc vì sao không dùng luôn các nền tảng tự động hóa như Ansible cho xong. Tôi không dùng Ansible chỉ để quản lý một danh sách gói. Ansible trở nên hữu ích khi tôi bắt đầu làm những việc như:

  • Cài gói
  • Cấu hình Git
  • Tạo các file cấu hình
  • Cấu hình Vim
  • Bật các dịch vụ
  • Cấu hình GNOME
  • Áp dụng thiết lập hệ thống

Hoặc khi tôi muốn cùng một cấu hình trên nhiều máy.

Với mục đích cài gói đơn giản, tôi dùng Bash. Với cấu hình hệ thống có thể lặp lại, tôi chuyển sang Ansible.

7. Cài Ansible

Ansible là công cụ tự động hóa IT mã nguồn mở, chạy trên dòng lệnh, viết bằng Python. Nó có thể cấu hình hệ thống, triển khai phần mềm và điều phối các luồng công việc nâng cao để hỗ trợ triển khai ứng dụng, cập nhật hệ thống, v.v.

Nó nổi tiếng là "không agent", nghĩa là quản lý các máy từ xa qua các giao thức kết nối tiêu chuẩn mà không cần cài phần mềm thường trú trên chúng.

Cách hoạt động

Bạn viết các chỉ thị mà con người đọc được bằng YAML (gọi là "playbook") khai báo trạng thái mong muốn của máy chủ. Ansible kết nối qua SSH (với Linux/Unix) hoặc WinRM (với Windows), kiểm tra trạng thái hiện tại và chỉ thực hiện thay đổi nếu cần để khớp với chỉ thị của bạn. Không cần thêm agent hay daemon trên các node được quản lý.

Những điểm chính

  • Kiến trúc không agent: Khác với các công cụ yêu cầu một agent thường trú trên mỗi máy chủ, Ansible dùng chính SSH daemon sẵn có (hoặc WinRM với Windows) để truyền tải. Điều này giảm chi phí bảo trì và loại bỏ nhu cầu quản lý việc cập nhật hay tương thích phần mềm agent.
  • Tính idempotent: Đây là nguyên tắc cốt lõi. Các module Ansible được thiết kế để có tính idempotent khi có thể, nghĩa là chúng chỉ thay đổi hệ thống khi trạng thái mong muốn chưa đạt được. Chạy cùng một playbook nhiều lần cho cùng một kết quả. Lưu ý: một số module (như command và shell) không có hành vi này mặc định và cần được thực thi thủ công.
  • Đơn giản nhờ YAML: Playbook được viết bằng YAML, một ngôn ngữ mà con người đọc được. Điều này khiến mã tự động hóa của bạn thường đọc như tài liệu, dễ tiếp cận cả với những người không phải lập trình viên chuyên nghiệp.
  • Mô hình đẩy: Bạn chạy Ansible từ một "Control Node" trung tâm, và nó đẩy các thay đổi cấu hình tới các "Managed Node" qua SSH (hoặc WinRM với Windows).

Một sự thật thú vị về Ansible

Dù Ansible nổi tiếng là "không agent", thực ra nó có dùng một agent rất nhỏ, tạm thời — nhưng chỉ trong chốc lát. Với mỗi tác vụ, Ansible kết nối tới các node được quản lý và đẩy tới đó những chương trình nhỏ gọi là Ansible module.

Những chương trình này được viết như mô hình tài nguyên của trạng thái mong muốn trên hệ thống. Ansible sau đó thực thi các module này (mặc định qua SSH) và xóa chúng khi hoàn tất. Điều này để lại máy chủ đúng như trước khi tự động hóa, không có phần mềm Ansible thường trú nào được cài.

Để cài Ansible trên Debian / Ubuntu, chạy:

sudo apt update
sudo apt install ansible

Kiểm tra phiên bản:

ansible --version

Kết quả mẫu:

ansible [core 2.16.3]
config file = None
configured module search path = ['/home/ostechnix/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
ansible python module location = /usr/lib/python3/dist-packages/ansible
ansible collection location = /home/ostechnix/.ansible/collections:/usr/share/ansible/collections
executable location = /usr/bin/ansible
python version = 3.12.3 (main, Apr 10 2024, 05:33:47) [GCC 13.2.0] (/usr/bin/python3)
jinja version = 3.1.2
libyaml = True

8. Tạo dự án Ansible

Với một máy để bàn cá nhân:

mkdir -p ~/ansible/debian-desktop
cd ~/ansible/debian-desktop

Khởi tạo Git:

git init

Cấu trúc ban đầu:

debian-desktop/
├── inventory.ini
└── site.yml

9. Tạo inventory

Tạo file inventory.ini:

inventory.ini

Thêm:

[desktop]
localhost ansible_connection=local

Điều này báo cho Ansible quản lý máy hiện tại của tôi theo cách cục bộ.

Kiểm tra bằng command:

ansible -i inventory.ini desktop -m ping

Kết quả mẫu:

localhost | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python3"
},
"changed": false,
"ping": "pong"
}

10. Tạo playbook

Tạo file site.yml:

nano site.yml

Thêm các dòng sau:

---
- name: Configure my Debian desktop
hosts: desktop
become: true
tasks:
- name: Update apt cache
ansible.builtin.apt:
update_cache: true
- name: Install desktop packages
ansible.builtin.apt:
name:
- git
- curl
- wget
- ca-certificates
- unzip
- build-essential
- firmware-cirrus
- papirus-icon-theme
- timeshift
- gnome-shell-extension-manager
- vim
- gnome-shell-extension-dashtodock
- gnome-themes-extra
- flatpak
- gnome-software-plugin-flatpak
- steam-installer
state: present

Một lần nữa, hãy thêm những packages mà nền tảng của bạn hỗ trợ vào playbook trên. Lưu và đóng lại.

Chạy playbook:

ansible-playbook -i inventory.ini site.yml --ask-become-pass

Kết quả mẫu:

BECOME password:
PLAY [Configure my Debian desktop] ********************************************************************************************************************************************************************************************************
TASK [Gathering Facts] ********************************************************************************************************************************************************************************************************************
ok: [localhost]
TASK [Update apt cache] *******************************************************************************************************************************************************************************************************************
changed: [localhost]
TASK [Install desktop packages] ***********************************************************************************************************************************************************************************************************
changed: [localhost]
PLAY RECAP ********************************************************************************************************************************************************************************************************************************
localhost : ok=3 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0

11. Khác biệt giữa script Bash và Ansible

Bash thường nói: Hãy chạy những command này.

Ansible thường nói: Hãy làm cho máy trông như thế này.

Ví dụ:

- name: Install Vim
ansible.builtin.apt:
name: vim
state: present

Nếu Vim chưa được cài, Ansible chỉ thị hệ thống cài nó. Nếu Vim đã được cài, nó chỉ đơn giản nói không làm gì.

Đây gọi là tính idempotent.

12. Thêm cấu hình

Khi việc cài gói đã hoạt động, Ansible cũng có thể quản lý cấu hình.

Ví dụ:

- name: Create Vim configuration
ansible.builtin.copy:
content: |
set number
set relativenumber
syntax on
dest: "{{ ansible_facts.user_dir }}/.vimrc"
mode: "0644"

Giờ Ansible không chỉ cài phần mềm. Nó đang cấu hình máy.

13. Chia nhỏ khi playbook phình to

Đừng vội lo về Ansible role ngay lập tức.

Nếu site.yml quá lớn, bạn có thể tách các tác vụ vào các file riêng:

debian-desktop/
ZXQPRO
PROTECTED0105QXZ
├── site.yml
├── packages.yml
├── git.yml
└── desktop.yml

site.yml là playbook chính. Nó import và chạy các tác vụ từ những file khác:

---
- name: Configure my Debian desktop
hosts: desktop
become: true
tasks:
- ansible.builtin.import_tasks: packages.yml
- ansible.builtin.import_tasks: git.yml
- ansible.builtin.import_tasks: desktop.yml

Mỗi file riêng có mục đích cụ thể:

  • packages.yml - chứa các tác vụ cài và quản lý các packages APT.
  • git.yml - chứa các tác vụ cấu hình Git.
  • desktop.yml - chứa các tác vụ cấu hình GNOME và các thiết lập máy để bàn khác.

Ví dụ, packages.yml có thể chứa:

---
- name: Install required packages
ansible.builtin.apt:
name:
- git
- curl
- wget
- vim
- flatpak
state: present

Điều này giữ site.yml nhỏ và giúp cấu hình dễ hiểu, dễ bảo trì hơn.

14. Cuối cùng, dùng Ansible role cho thiết lập phức tạp

Nếu dự án trở nên lớn hơn nhiều, bạn có thể đưa vào Ansible role.

Cấu trúc cuối cùng có thể trông như:

debian-desktop/
├── inventory.ini
├── site.yml
└── roles/
├── packages/
├── git/
├── vim/
└── gnome/

Mỗi role nhóm tất cả các tác vụ, file, template, biến và cấu hình liên quan đến một lĩnh vực cụ thể.

Ví dụ:

  • packages - quản lý các packages đã cài.
  • git - quản lý cấu hình Git.
  • vim - quản lý cấu hình Vim.
  • gnome - quản lý GNOME và cấu hình máy để bàn.

Đừng bắt đầu bằng role. Với một máy cá nhân, hãy bắt đầu bằng một site.yml duy nhất. Nếu nó trở nên lớn, hãy tách thành các file như packages.yml, git.yml và desktop.yml. Chỉ đưa role vào khi dự án đã phát triển đủ để chúng mang lại lợi ích thực sự.

15. Các lệnh Ansible hữu ích

Kiểm tra Ansible:

ansible -i inventory.ini desktop -m ping

Chạy playbook:

ansible-playbook -i inventory.ini site.yml --ask-become-pass

Chạy thử (dry run):

ansible-playbook -i inventory.ini site.yml --check --ask-become-pass

Xem thêm đầu ra:

ansible-playbook -i inventory.ini site.yml --ask-become-pass -v

16. Giữ thiết lập trong Git

Với script Bash:

cd ~/scripts
git init

Với dự án Ansible:

cd ~/ansible/debian-desktop
git init

Dần dần, dự án Ansible có thể trở thành mô tả chuẩn cho thiết lập máy để bàn của tôi.

17. Còn Fedora hay các bản phân phối dựa trên RHEL thì sao?

Cấu trúc Bash của script có thể tái sử dụng trên Fedora và các bản phân phối dựa trên RHEL khác, nhưng bạn không nên cho rằng chỉ cần thay apt bằng dnf là đủ.

Trên Debian:

sudo apt update
sudo apt install -y "${PACKAGES[@]}"

Trên các hệ thống Fedora/dựa trên RHEL, việc cài gói thường dùng:

sudo dnf install -y "${PACKAGES[@]}"

Tuy nhiên, tên gói có thể khác nhau giữa các bản phân phối.

Ví dụ:

Debian              Fedora/RHEL
-------             ----------
git                 git
curl                curl
wget                wget
ca-certificates     ca-certificates
unzip               unzip
build-essential     gcc gcc-c++ make

Một số packages có thể có tên hoàn toàn khác, được cung cấp bởi các kho khác nhau, hoặc không tồn tại ở dạng tương tự.

Vì vậy, với một thiết lập cá nhân, thường sạch hơn nếu giữ các script riêng:

install-debian-essential-packages.sh
install-fedora-essential-packages.sh

Script Debian có thể dùng:

sudo apt update
sudo apt install -y "${PACKAGES[@]}"

trong khi script Fedora có thể dùng:

sudo dnf install -y "${PACKAGES[@]}"

với một danh sách gói riêng cho Fedora.

Vì sao không làm một script cho tất cả?

Có thể phát hiện bản phân phối:

if command -v apt >/dev/null 2>&1; then
sudo apt update
sudo apt install -y "${PACKAGES[@]}"
elif command -v dnf >/dev/null 2>&1; then
sudo dnf install -y "${PACKAGES[@]}"
else
echo "Unsupported package manager."
exit 1
fi

Nhưng việc này trở nên phức tạp hơn khi tên gói khác nhau.

Với một thiết lập cá nhân đơn giản, các script riêng sẽ dễ hiểu và dễ bảo trì hơn.

Nếu cấu hình cuối cùng cần hỗ trợ nhiều bản phân phối và trở nên phức tạp hơn nhiều, đó là thời điểm tốt để cân nhắc Ansible.

18. Kết luận

Như bạn thấy, chúng ta có thể dùng một script Bash hậu cài đặt đơn giản để tránh cài thủ công cùng một danh sách packages lặp đi lặp lại. Nếu bạn muốn tự động hóa và tái tạo cấu hình của toàn bộ hệ thống, bạn có thể dùng Ansible.

Đừng đưa Ansible vào cho đến khi vấn đề đủ lớn để cần đến nó.

Đừng làm phức tạp mọi thứ. Hãy bắt đầu đơn giản. Tự động hóa những gì trở nên lặp lại. Đưa Ansible vào khi chính cấu hình là thứ cần quản lý.