Cài Postgres local — psql + GUI tool trong 15 phút
3 cách cài (Docker recommend, Postgres.app, brew). Apply TaskFlow schema. Tour psql + DBeaver/TablePlus/pgAdmin. Sẵn sàng query bài đầu tiên.
Ba bài trước giải thích tại sao cần database, relational model là gì, và cách vẽ ER diagram trước khi gõ DDL. Bây giờ cần Postgres thực sự chạy trên máy để gõ SELECT đầu tiên — lý thuyết không thay được thực hành trên data thật.
Bài này 15 phút: chọn cách cài phù hợp, khởi động Postgres, kết nối bằng psql, mở GUI tool, và apply schema TaskFlow. Cuối bài bạn có psql sẵn sàng, 10 user trong bảng users, và hiểu 8 lệnh psql thiết yếu nhất.
1. Analogy — Setup môi trường dev vs đặt đồ ăn
Cài Postgres local giống chọn cách chuẩn bị bữa ăn — cùng kết quả cuối cùng (có đồ ăn), nhưng mức độ kiểm soát và công sức khác nhau.
| Cách chuẩn bị | Cách cài Postgres |
|---|---|
| Gọi combo set sẵn từ nhà hàng | Docker Compose — config sẵn, chạy một lệnh |
| Mua nguyên liệu siêu thị, tự nấu | Postgres.app (macOS) — cài binary native, GUI built-in |
| Trồng rau, nuôi gà, nấu từ đầu | brew/apt install — full control mọi thứ |
| Combo nhanh nhưng khó tùy chỉnh | Docker: port, volume, version đều config được qua YAML |
| Siêu thị chỉ có ở một thành phố | Postgres.app chỉ chạy trên macOS |
| Nuôi gà cần nhiều bước nhất | brew/apt cần tự tạo cluster, config auth, tạo database |
Docker = combo set sẵn: nhanh, reproducible, dọn sạch một lệnh. Chọn Docker nếu bạn đang setup dev environment mới — đặc biệt khi OLHub repo đã có sẵn docker-compose.yml.
2. 3 cách cài — chọn cách nào
| Cách | Ưu điểm | Nhược điểm | Khi nào dùng |
|---|---|---|---|
| Docker Compose (recommend) | Reproducible, dọn sạch dễ, OLHub repo có sẵn config | Cần Docker Desktop installed, thêm port mapping | Mọi dev mới, mọi OS |
| Postgres.app (macOS) | Native binary, GUI built-in, cài dễ | Chỉ macOS, không reproducible giữa máy | Casual dev macOS muốn nhanh |
| brew/apt install | Native, control phiên bản, không cần Docker | Phải tự config, dễ conflict với Postgres hệ thống | Power user quen CLI |
Bài này hướng dẫn chi tiết cả 3 cách. Làm theo một cách, bỏ qua hai cách còn lại.
3. Cài Docker Compose (recommend) — từng bước
Yêu cầu: Docker Desktop đã cài và đang chạy.
Bước 1 — Chuẩn bị docker-compose.yml.
Nếu bạn đã clone OLHub repo, file này đã có sẵn. Nếu chưa, tạo file docker-compose.yml với nội dung tối thiểu:
services:
postgres:
image: postgres:16-alpine
ports:
- "5433:5432"
environment:
POSTGRES_DB: olhub
POSTGRES_USER: olhub
POSTGRES_PASSWORD: olhub_secret_2026
volumes:
- postgres_data:/var/lib/postgresql/data
volumes:
postgres_data:
Bước 2 — Khởi động Postgres.
docker compose up -d postgres
Verify đang chạy:
docker compose ps postgres
Output mong đợi:
NAME IMAGE COMMAND SERVICE CREATED STATUS PORTS
olhub-postgres postgres:16-alpine "docker-entrypoint.s…" postgres 5 seconds ago Up 4 seconds (healthy) 0.0.0.0:5433->5432/tcp
Bước 3 — Kết nối bằng psql.
docker compose exec postgres psql -U olhub -d olhub
Output mong đợi:
psql (16.x)
Type "help" for help.
olhub=#
Prompt olhub=# nghĩa là bạn đã kết nối vào database olhub với quyền superuser. Gõ \q để thoát.
Connection string từ host (dùng khi kết nối GUI tool hoặc app):
postgresql://olhub:olhub_secret_2026@localhost:5433/olhub
Lưu ý port 5433 — OLHub map host port 5433 vào container port 5432 để tránh conflict với Postgres khác đang chạy trên máy.
Nếu thấy lỗi Error starting userland proxy: listen tcp 0.0.0.0:5433: bind: address already in use, có process khác đang dùng port đó. Kiểm tra: lsof -i :5433. Giải pháp: (a) stop process kia, (b) đổi host port trong docker-compose.yml từ 5433 sang port khác, ví dụ 5434. Nếu port 5432 bị chiếm (Postgres local khác), OLHub đã dùng 5433 để tránh xung đột — đây là lý do thiết kế đó.
Dọn sạch khi không cần:
docker compose down # stop container, giu data
docker compose down -v # stop container + xoa volume (mat data)
4. Cài Postgres.app (macOS) — alternative
Dành cho: macOS dev muốn native binary, không muốn Docker overhead.
Bước 1 — Download và cài.
Vào postgresapp.com, download file .dmg, mở và kéo Postgres.app vào thư mục Applications.
Bước 2 — Khởi động và config.
Mở Postgres.app từ Applications. Icon xuất hiện trên menu bar. Click "Initialize" để tạo cluster lần đầu. Click "Start" để start server.
Mặc định: port 5432, không password (trust mode), username = OS username (ví dụ alice).
Bước 3 — Kết nối bằng psql.
Postgres.app bundle psql binary riêng — không dùng lệnh psql hệ thống. Mở bằng:
/Applications/Postgres.app/Contents/Versions/latest/bin/psql -d postgres
Hoặc click đúp vào tên database trong cửa sổ Postgres.app để mở psql thẳng.
Sau khi cài Postgres.app, gõ psql trong terminal báo command not found. Lý do: Postgres.app không tự thêm binary vào PATH. Fix theo hướng dẫn trong app: thêm dòng sau vào ~/.zshrc hoặc ~/.bashrc:
export PATH="/Applications/Postgres.app/Contents/Versions/latest/bin:$PATH"
Sau đó source ~/.zshrc và gõ lại psql.
5. Cài qua brew (macOS) / apt (Linux) — power user
macOS với Homebrew:
brew install postgresql@16
brew services start postgresql@16
Tạo database mới:
createdb taskflow
psql -d taskflow
Linux Ubuntu/Debian:
sudo apt update
sudo apt install -y postgresql-16 postgresql-contrib
sudo systemctl start postgresql
sudo systemctl enable postgresql
Kết nối qua socket với user hệ thống postgres:
sudo -u postgres psql
Sau brew services start postgresql@16, chạy psql thẳng báo lỗi database "username" does not exist. Brew tạo cluster nhưng không tạo database tên user. Phải chạy createdb ten_database riêng, ví dụ createdb taskflow. Linux apt thì có sẵn database postgres với user postgres — kết nối qua sudo -u postgres psql.
6. GUI tool — chọn cái nào
| Tool | Platform | Miễn phí? | Điểm mạnh | Khi nào dùng |
|---|---|---|---|---|
| DBeaver Community | Cross-platform | Miễn phí | Universal multi-DB, ER diagram, SQL editor mạnh | Power user, dùng nhiều loại database |
| TablePlus | macOS/Windows | Freemium (xem giá hiện tại tại tableplus.com) | Native, nhanh, giao diện đẹp | macOS dev, không tiếc tiền bản quyền |
| pgAdmin 4 | Cross-platform | Miễn phí, chính thức | Full PG features, monitoring, query explain | Cần admin chuyên sâu, đọc query plan |
| psql (CLI) | Cross-platform | Miễn phí, có sẵn | Script automation, không cần UI | Quen CLI, viết migration, shell scripting |
Recommend cho bài này: DBeaver Community — miễn phí hoàn toàn, đủ tính năng cho toàn khoá học, chạy trên mọi OS.
Kết nối DBeaver với OLHub Docker:
Mở DBeaver → New Database Connection → PostgreSQL. Nhập:
- Host:
localhost - Port:
5433 - Database:
olhub - Username:
olhub - Password:
olhub_secret_2026
Click "Test Connection" — báo "Connected" là xong.
7. psql essentials — 8 lệnh phải nhớ
| Lệnh | Mô tả |
|---|---|
\l | List tất cả database trong cluster |
\c <db> | Connect sang database khác |
\dt | List table trong schema hiện tại (public) |
\d <table> | Describe table: columns, types, indexes, constraints |
\du | List user/role trong cluster |
\timing on | Bật hiển thị thời gian thực thi mỗi query |
\x | Toggle expanded display — mỗi column xuống dòng riêng, dễ đọc khi nhiều column |
\q | Quit psql |
Demo nhanh — thử ngay sau khi kết nối:
olhub=# \l
List of databases
Name | Owner | Encoding | Collate | Ctype |
-----------+----------+----------+-------------+-------------+
olhub | olhub | UTF8 | en_US.utf8 | en_US.utf8 |
postgres | postgres | UTF8 | en_US.utf8 | en_US.utf8 |
olhub=# \dt
Did not find any relations.
olhub=# \q
\dt trả về "Did not find any relations" vì database olhub chưa có table nào — bước tiếp theo sẽ fix điều này.
8. Apply TaskFlow schema
Schema TaskFlow gồm 5 bảng — DDL đầy đủ tour ở bài M01.5 (tour TaskFlow schema) của khoá này (section 3–7). Bài này chỉ cần copy-paste vào psql để DB sẵn sàng cho M02 trở đi.
Bước 1 — Tạo database taskflow:
docker compose exec postgres psql -U olhub -d olhub -c "CREATE DATABASE taskflow;"
Bước 2 — Apply schema DDL (paste 5 CREATE TABLE từ bài M01.5 vào psql, hoặc chạy heredoc):
docker compose exec -T postgres psql -U olhub -d taskflow <<'EOF'
CREATE TABLE users (
id BIGSERIAL PRIMARY KEY,
email TEXT UNIQUE NOT NULL,
name TEXT NOT NULL,
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
CREATE TABLE projects (
id BIGSERIAL PRIMARY KEY,
owner_id BIGINT NOT NULL REFERENCES users(id),
name TEXT NOT NULL,
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
CREATE TABLE project_members (
user_id BIGINT NOT NULL REFERENCES users(id),
project_id BIGINT NOT NULL REFERENCES projects(id),
role TEXT NOT NULL CHECK (role IN ('owner', 'member', 'viewer')),
joined_at TIMESTAMPTZ NOT NULL DEFAULT now(),
PRIMARY KEY (user_id, project_id)
);
CREATE TABLE tasks (
id BIGSERIAL PRIMARY KEY,
project_id BIGINT NOT NULL REFERENCES projects(id),
assignee_id BIGINT REFERENCES users(id),
title TEXT NOT NULL,
status TEXT NOT NULL CHECK (status IN ('todo', 'doing', 'done', 'archived')) DEFAULT 'todo',
due_at TIMESTAMPTZ,
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
CREATE TABLE comments (
id BIGSERIAL PRIMARY KEY,
task_id BIGINT NOT NULL REFERENCES tasks(id),
user_id BIGINT NOT NULL REFERENCES users(id),
body TEXT NOT NULL,
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
EOF
Bước 3 — Load seed nhỏ (10 user + 5 project — đủ cho M02–M03):
docker compose exec -T postgres psql -U olhub -d taskflow <<'EOF'
INSERT INTO users (email, name) VALUES
('[email protected]', 'Nguyen Van An'),
('[email protected]', 'Tran Thi Binh'),
('[email protected]', 'Le Hoang Cuong'),
('[email protected]', 'Pham Tien Dung'),
('[email protected]', 'Hoang Thi Em'),
('[email protected]', 'Vo Minh Fan'),
('[email protected]', 'Bui Quoc Giang'),
('[email protected]', 'Do Thi Huong'),
('[email protected]', 'Mai Van Inh'),
('[email protected]', 'Ngo Hoang Khoa');
INSERT INTO projects (owner_id, name) VALUES
(1, 'OLHub Platform'),
(1, 'Marketing Site'),
(2, 'Mobile App'),
(3, 'Internal Dashboard'),
(4, 'Data Pipeline');
EOF
Verify thành công:
docker compose exec postgres psql -U olhub -d taskflow -c "SELECT count(*) FROM users;"
Output mong đợi:
count
-------
10
(1 row)
10 user trong bảng users — schema và seed data đã load đúng.
Seed nhỏ chỉ insert 10 user và 5 project để bài M02–M03 query nhẹ. Các bảng project_members, tasks, comments còn rỗng — sẽ được sinh đầy đủ bằng script pgbench-style ở Module 7 (EXPLAIN deep) khi cần dataset lớn để bench. Nếu SELECT count(*) FROM tasks trả 0 — đó là expected.
Bài sau sẽ tour toàn bộ schema: 5 table, constraint, và mapping về ER diagram của bài M01.3.
9. Pitfall — 3 lỗi setup phổ biến
Lỗi 1 — "Connection refused"
psql: error: connection to server at "localhost" (127.0.0.1), port 5433 failed: Connection refused
Nguyên nhân: Postgres container chưa start hoặc đang khởi động. Kiểm tra: docker compose ps postgres. Nếu status không phải Up (healthy), chạy docker compose up -d postgres và đợi thêm 5-10 giây.
Lỗi 2 — "Authentication failed for user"
psql: error: connection to server failed: FATAL: password authentication failed for user "alice"
Nguyên nhân: typo password hoặc dùng sai username. OLHub dùng user olhub, không phải username hệ thống hay postgres. Kiểm tra lại connection string: postgresql://olhub:olhub_secret_2026@localhost:5433/olhub.
Postgres tạo sẵn superuser postgres khi init cluster. OLHub tạo riêng user olhub với password trong docker-compose.yml. Dùng psql -U postgres sẽ báo authentication failed vì container không có user đó (trust mode không được bật). Luôn dùng -U olhub khi kết nối vào OLHub Docker.
Lỗi 3 — Port conflict
Error response from daemon: driver failed programming external connectivity:
bind for 0.0.0.0:5433 failed: port is already allocated
Nguyên nhân: port 5433 đang bị process khác dùng. Kiểm tra: lsof -i :5433. Nếu là Docker container cũ, chạy docker compose down trước. Nếu là process khác, đổi host port trong docker-compose.yml sang 5434 hoặc port trống khác.
10. Applied — workflow dev hàng ngày
Sau khi setup xong, workflow thực tế sẽ trở thành:
Buổi sáng — start môi trường:
docker compose up -d postgres
Truy vấn nhanh trong terminal:
docker compose exec postgres psql -U olhub -d taskflow
Gõ lệnh xong, \q để thoát.
Alias tiện lợi — thêm vào ~/.zshrc hoặc ~/.bashrc:
alias psqltf='docker compose exec postgres psql -U olhub -d taskflow'
Sau đó chỉ cần gõ psqltf để vào psql taskflow.
Snapshot trước khi experiment:
docker compose exec postgres pg_dump -U olhub -d taskflow > taskflow-snapshot.sql
Để rollback về snapshot:
docker compose exec postgres psql -U olhub -d taskflow -c "DROP SCHEMA public CASCADE; CREATE SCHEMA public;"
docker compose exec -T postgres psql -U olhub -d taskflow < taskflow-snapshot.sql
Snapshot giúp thực hành thoải mái — xóa nhầm bảng hay data thì restore lại trong vài giây, không cần setup lại từ đầu.
11. Deep Dive — Postgres setup
- PostgreSQL Documentation — Ch.18 "Server Setup and Operation" — reference chính thức cho mọi khía cạnh: config file
postgresql.conf, startup/shutdown, connection limits, logging, authentication (pg_hba.conf). Đọc khi cần hiểu sâu cơ chế, không chỉ cách dùng. - PostgreSQL: Up and Running (Obe & Hsu, 4th ed) — Ch.1 "Why PostgreSQL?" + Ch.2 "Database Administration" — practical guide với example cụ thể cho admin task: tạo role, backup, restore, basic monitoring. Ch.2 là tài liệu nhanh nhất để nắm admin workflow không cần đọc full PG docs.
docker-compose.ymlcủa OLHub — đọc để hiểu chi tiết: healthcheck config, port mapping, volume persistence, và biến môi trường. Đây là config thực tế đang chạy production.
Ghi chú: Đọc PG docs Ch.18 khi cần hiểu cơ chế server. "Up and Running" Ch.1-2 cho hands-on admin nhanh. OLHub docker-compose.yml để hiểu config cụ thể của project này.
12. Tóm tắt
- 3 cách cài: Docker Compose (recommend — reproducible, dọn sạch dễ), Postgres.app (macOS native, nhanh), brew/apt (full control, nhiều bước nhất).
- OLHub map port 5433 → 5432 — host port
5433tránh conflict với Postgres khác trên máy; connection string:postgresql://olhub:olhub_secret_2026@localhost:5433/olhub. - 3 GUI tool + 1 CLI: DBeaver (free, cross-platform, recommend), TablePlus (macOS, freemium), pgAdmin 4 (free, official, admin chuyên sâu) + psql CLI (free, bundled, scripting).
- 8 psql lệnh thiết yếu:
\l,\c,\dt,\d,\du,\timing on,\x,\q. - Schema TaskFlow apply qua 3 heredoc command (DDL + seed inline trong section 8) — verify với
SELECT count(*) FROM users→ 10 rows. - 3 lỗi phổ biến: "Connection refused" (Postgres chưa start), "Authentication failed" (sai user/password), port conflict (5433 occupied).
- Bài tiếp theo: Module 1 bài 5 của khoá này sẽ tour toàn bộ TaskFlow schema — đọc DDL, hiểu constraint, và xem sample data.
13. Tự kiểm tra
Q1Vì sao OLHub map host port 5433 thay vì dùng default 5432? Nếu một dev khác trên cùng team cũng đang chạy Postgres local thì sao?▸
Port 5432 là port default của Postgres. Nếu dev đã cài Postgres native (brew, apt, Postgres.app) và đang chạy, port đó đã bị chiếm. Docker container cố gắng bind thêm vào port 5432 sẽ báo "port already allocated" và không start được.
OLHub dùng host port 5433 để tránh xung đột: Postgres native chạy trên 5432, OLHub Docker chạy trên 5433 — cả hai cùng tồn tại trên một máy mà không conflict.
Nếu dev khác trong team cũng chạy OLHub Docker, mỗi người chạy trên máy riêng — không có conflict vì port binding là per-machine. Conflict chỉ xảy ra khi hai process trên cùng một máy cùng bind một port.
Q2Phân biệt khi nào dùng psql CLI và khi nào dùng GUI tool. Cho 2 task ví dụ phù hợp cho mỗi cái.▸
psql CLI phù hợp khi:
- Chạy migration script tự động trong CI/CD pipeline — không cần UI, chỉ cần pipe file vào psql.
- Viết alias hoặc shell script để query nhanh định kỳ, ví dụ kiểm tra row count sau mỗi lần import data.
GUI tool phù hợp khi:
- Explore schema lần đầu — DBeaver hiển thị cây table, column type, FK relationship dưới dạng ER diagram, nhanh hơn nhiều lần
\dliên tiếp. - Debug query phức tạp — pgAdmin 4 và DBeaver hiển thị query execution plan dạng đồ họa, dễ thấy đâu là bottleneck hơn là đọc text output của
EXPLAIN ANALYZE.
Nguyên tắc: CLI cho automation và scripting; GUI cho exploration và debugging tương tác.
Q3Bạn cài Postgres bằng brew và start service. Sau đó chạy `docker compose up -d postgres` trong OLHub repo thì báo lỗi port conflict. Diagnose và fix?▸
Brew Postgres chạy trên port 5432 (default). OLHub Docker dùng host port 5433 — nếu báo conflict trên port 5433, có nghĩa có gì đó khác đang bind port đó (hiếm gặp). Nếu conflict trên 5432, có nghĩa Docker đang cố bind port 5432 — không phải do OLHub config mà có thể do file compose khác.
Diagnose: lsof -i :5433 và lsof -i :5432 để xem process nào đang dùng. Nếu là brew Postgres trên 5433 (không phải mặc định — nhưng có thể bạn đã đổi config), chạy brew services stop postgresql@16.
Fix chuẩn cho OLHub: brew Postgres chạy 5432, OLHub Docker chạy 5433 — hai cái không conflict. Nếu vẫn conflict, kiểm tra file docker-compose.yml xem port mapping có đúng 5433:5432 không, và chắc chắn không có Docker container cũ nào đang giữ port.
Q4Bạn chạy `\dt` trong psql và thấy 'Did not find any relations' dù đã CREATE TABLE trước đó. Nguyên nhân có thể là gì?▸
Có hai nguyên nhân phổ biến:
- Đang ở sai database:
\dtchỉ list table trong database hiện tại. NếuCREATE TABLEchạy trong databasetaskflownhưng hiện tại đang connect vào databaseolhub, không thấy table nào là đúng. Fix: dùng\c taskflowđể switch sang database đúng, sau đó\dtlại. - Table ở schema khác public:
\dtmặc định chỉ show table trong schemapublic. Nếu table được tạo trong schema khác (vdapp.users), dùng\dt app.*hoặc\dt *.*để xem tất cả schema.
Kiểm tra nhanh: SELECT current_database(); để biết đang ở database nào, và SELECT table_schema, table_name FROM information_schema.tables WHERE table_type = 'BASE TABLE'; để thấy mọi table trong mọi schema.
Q5Bạn muốn rollback database về state trước khi experiment một loạt ALTER TABLE và DELETE. Lệnh nào? Tradeoff so với dùng migration tool như Flyway/Liquibase?▸
Snapshot và restore bằng pg_dump:
- Snapshot trước:
docker compose exec postgres pg_dump -U olhub taskflow > snapshot.sql - Restore: drop schema và load lại từ file snapshot.
Ưu điểm pg_dump: nhanh, không cần setup thêm tool, hoạt động với mọi Postgres instance, phù hợp cho experiment cá nhân.
Nhược điểm: thủ công, không tự động theo dõi lịch sử thay đổi, snapshot có thể bị lỗi thời nếu schema tiếp tục thay đổi sau khi tạo. Restore mất thời gian nếu data lớn.
Migration tool (Flyway, Liquibase, Prisma Migrate): mỗi thay đổi schema là một file migration có version — apply theo thứ tự, roll back theo thứ tự ngược. Ưu điểm: lịch sử rõ ràng, team cùng sync schema dễ dàng, CI/CD tự động apply. Nhược điểm: Postgres không có built-in down migration — Prisma 7 (OLHub dùng) cũng vậy; muốn rollback phải viết reverse migration thủ công.
Với môi trường học tập, pg_dump snapshot là đủ. Với production, dùng migration tool và không dựa vào pg_dump để rollback schema.
Bài tiếp theo: Tour TaskFlow schema — đọc DDL hiểu constraint
Bài này có giúp bạn hiểu bản chất không?