---
id: linux-packages
title: "Package manager"
shortTitle: "Package manager"
track: linux
trackTitle: "Linux & Shell Scripting"
order: 7
level: core
status: published
estimatedMinutes: 30
prerequisites:
  - linux-ssh
next: linux-editors
reviewedAgainst: 2026-10-12
sources:
  - title: "apt(8)"
    url: https://manpages.debian.org/bookworm/apt/apt.8.en.html
  - title: "dnf(8)"
    url: https://dnf.readthedocs.io/en/latest/command_ref.html
---

# Package manager

Package manager cài phần mềm từ kho của distro, tự kéo dependency, và gỡ ra sạch sẽ được. `curl | sh` không làm được những việc đó.

## Để làm gì

Sau bài này, bạn biết máy đang dùng `apt` hay `dnf`, xem được version của một gói mà không cần cài, và viết được lệnh cài chạy lặp lại an toàn trong script.

## Gồm những gì

- Debian, Ubuntu: `apt update`, `apt install`, `apt-cache policy`.
- Fedora, RHEL: `dnf`.
- Vì sao không trộn lệnh của hai họ distro.

Bài này không nói về snap, flatpak hay build từ source. Nếu một gói không có trong kho, hãy tìm bản phát hành chính thức của phần mềm đó thay vì thêm repo lạ vào server.

## Dùng khi nào

Bạn dùng package manager để cài `nginx`, `git`, `jq` trên VM. Với Docker image, việc cài nằm trong Dockerfile và dùng package manager của base image; ví dụ container `debian` không có `dnf`.

Đừng `apt install` trên máy production chỉ để thử. Hãy thử ở lab hoặc trong image, rồi deploy image mới.

## Kiến thức cốt lõi

Kho (repository) gồm danh sách gói và các file `.deb` hoặc `.rpm`. `apt update` chỉ tải danh sách về, chưa cài gì. `apt install nginx` mới tải gói cùng dependency rồi cấu hình.

Nếu không `update`, `apt` có thể cài bản cũ theo danh sách từ tuần trước, hoặc báo không tìm thấy gói mới.

`apt-cache policy nginx` in version candidate và kho nào đang cung cấp gói, không cần quyền root. Lệnh tương ứng bên họ RHEL là `dnf info nginx`.

Khi cần mọi máy chạy cùng một bản, bạn pin version: `apt install nginx=1.24.0-2ubuntu7`. Version đó phải còn trong kho; khi nâng distro, bản đã pin có thể không còn nữa.

`apt remove` gỡ gói, còn `apt purge` gỡ luôn file cấu hình trong `/etc`. Đọc kỹ danh sách trước khi purge.

## Lệnh và code mẫu

Debian hoặc Ubuntu:

```bash
apt-cache policy nginx
sudo apt update
sudo apt install --no-install-recommends jq
jq --version
```

Fedora hoặc RHEL:

```bash
dnf info nginx
sudo dnf install -y jq
```

Kiểm tra họ distro trước khi chọn lệnh:

```bash
. /etc/os-release && printf '%s\n' "$ID"
```

## Thực hành

1. In `$ID`.
2. Chạy `apt-cache policy curl` hoặc `dnf info curl`, tùy máy có lệnh nào.
3. Nếu máy này không phải lab thì đừng cài thêm gói. Chỉ đọc version đang cài ở dòng `Installed`.

## Kết quả mong đợi

Bạn biết máy dùng package manager nào và version candidate của `curl`. Máy không bị thêm gói lạ nào.

## Checklist

- [ ] Trong script, chạy `apt update` trước `apt install`.
- [ ] Mỗi image chỉ dùng một họ lệnh, không gọi cả `apt` lẫn `dnf`.
- [ ] Khi thêm repo bên thứ ba, ghi rõ URL và lý do, không copy nguyên một dòng `curl | sh` vào VM.

## Thẻ ôn

### linux-packages-update
kind: command
cue: Trên Debian, `apt update` chỉ tải danh sách gói, chưa cài gì. Bỏ bước đó thì `apt install` dùng danh sách cũ.

Q: Script cài nginx trên Debian đi thẳng vào `apt install` và hoặc báo không thấy gói, hoặc cài một bản cũ hơn bản đang có trên kho. `apt update` làm gì, và vì sao nó phải đứng trước?

A: `apt update` chỉ tải lại danh sách gói và version từ các kho đã cấu hình. Nó chưa cài và chưa nâng gói nào. Không có bước đó, `apt` dùng danh sách đã cache trên máy, tức cái nhìn của lần update trước. Gói mới thêm vào kho sẽ như không tồn tại, và gói đã có thể được cài đúng bản của tuần trước. `apt install` mới là lệnh tải gói cùng dependency rồi cài. Script cần cả hai, đúng thứ tự.

### linux-packages-family
kind: decide
cue: Một image một họ lệnh. Debian và Ubuntu dùng `apt`. Họ RHEL dùng `dnf`. Container `debian` không có `dnf`.

Q: Một Dockerfile dựa trên image Debian, và bạn copy một đoạn cài gói viết bằng `dnf` từ máy RHEL. Lệnh đó chạy được trong image không?

A: Không. Mỗi họ phân phối có trình quản lý gói riêng, và image chỉ có trình của họ đó. Debian và Ubuntu dùng `apt`. Họ RHEL dùng `dnf`. Image `debian` không cài sẵn `dnf`, nên lệnh fail trước cả khi tới tên gói. Chọn base image nào thì viết đúng họ lệnh của image đó, đừng trộn script của hai họ vào một file.

### linux-packages-pin
kind: command
cue: Mười máy cần cùng một bản thì đừng cài tay từng VM. Cài qua playbook hoặc image, và pin version khi cần khóa bản.

Q: Mười VM cần chạy cùng một bản nginx. Bạn định SSH vào từng máy và `apt install nginx`. Máy thứ mười dễ lệch chỗ nào, và khi cần khóa đúng một bản thì câu lệnh trông thế nào?

A: Mỗi lần cài tay là một thời điểm khác nhau. Kho đã kịp có bản mới thì máy sau nhận bản khác máy trước, dù câu lệnh giống hệt. Cài qua playbook hoặc đóng vào image để mười máy nhận cùng một lần khai báo. Khi cần khóa bản, pin version còn trong kho, ví dụ `apt install nginx=1.24.0-2ubuntu7`. Không ghi version thì bạn đang xin "bản mới nhất tại thời điểm máy đó chạy", không phải "cùng một bản".

### linux-packages-third-party
kind: trap
cue: Hướng dẫn thêm repo bên thứ ba bằng `curl | sh` thì đừng copy nguyên dòng đó lên VM. Ghi rõ URL và lý do.

Q: Tài liệu của một kho gói bên thứ ba bảo dán `curl` một URL rồi pipe vào `sh` để thêm repo. Trên VM sẽ chạy dịch vụ, có làm theo nguyên dòng đó không?

A: Không copy nguyên dòng vào VM. `curl | sh` chạy luôn nội dung vừa tải, bạn không có file để đọc trước khi nó sửa danh sách kho và có thể cài thêm thứ khác. Ghi rõ URL của kho, lý do cần kho đó, và các lệnh thêm key hay source list thành những bước đọc được trong playbook hoặc trong ghi chú máy. Kho bên thứ ba vẫn thêm được, nhưng không bằng một pipe không để lại dấu vết bạn đã xem gì.

## Lỗi thường gặp

**`apt install` báo không thấy gói bạn vừa đọc được trên mạng.** Thường là do danh sách gói local đã cũ, nên chạy `apt update`. Nếu vẫn không thấy, gói đó thuộc distro khác, hoặc nằm trong một component chưa bật trong `/etc/apt/sources.list`.

**Cài nginx bằng tay trên mười VM.** Đến máy thứ mười một, version đã lệch so với mười máy trước. Hãy cài qua playbook hoặc trong image, để lần nào cũng ra cùng một bản.

## Nguồn

1. [apt(8)](https://manpages.debian.org/bookworm/apt/apt.8.en.html) — `update`, `install`, `remove`.
2. [DNF command reference](https://dnf.readthedocs.io/en/latest/command_ref.html) — `install`, `info`.

## Tiếp theo

[Vim và nano](./06-editors.md)
