展示一些使用 Docker Compose 配置 PostgreSQL 本地開發環境的技巧。
從基本設定開始:
version: <font>"3" services: postgres: image: postgres:15.1-alpine container_name: postgres environment: - POSTGRES_DB=postgres - POSTGRES_USER=postgres - POSTGRES_PASSWORD=Password12! ports: - "5432:5432"
|
最基本的設定,此外還透過環境變數新增兩個額外的配置:
- POSTGRES_DB - 指示 PostgreSQL 容器自動建立具有提供的名稱的預設資料庫,
- POSTGRES_USER - 設定預設使用者名稱。
- POSTGRES_PASSWORD - 為 PostgreSQL 使用者設定自定義密碼。
如果我們執行:
docker-compose up
然後,將建立一個新的 PostgreSQL 容器,並在localhost:5432上可用(因為我們也向主機公開了這個埠)。我們現在可以嘗試連線我們的應用程式。
如果我們想設定一個基本的資料庫結構,比如一組預定義的表、索引、資料等,該怎麼辦?
大多數關聯式資料庫都支援一個特殊的docker-entrypoint-initdb.d資料夾。此資料夾用於在首次建立容器時自動初始化資料庫。您可以將.sql或.sh指令碼放在那裡,Docker 會自動執行。這隻會在容器首次啟動時發生,而不會在後續重新啟動時發生。
讓我們嘗試一下並新增一個名為001-init.sql的基本指令碼:
BEGIN;
-- structure setup
CREATE TABLE users ( id SERIAL PRIMARY KEY, username VARCHAR(50) NOT NULL, email VARCHAR(100) NOT NULL );
-- data setup
INSERT INTO users (username, email) VALUES ('user1', 'user1@example.com');
INSERT INTO users (username, email) VALUES ('user2', 'user2@example.com');
COMMIT;
|
這是一個簡單的指令碼,表明我們可以以事務方式執行指令碼(參見BEGIN和COMMIT)。我們還可以設定資料庫結構並插入一些資料。
我們可以將指令碼拆分為兩個檔案:001-init-structure.sql和002-init-data.sql。它們將按字母順序執行。
如何將它放入容器中呢?我們可以使用volumes卷來實現這一點:
卷可以儲存容器資料。您可以重新啟動容器,資料將保留。它還允許將主機作業系統檔案掛載/繫結到容器。它可以雙向進行,您可以將檔案傳送到容器,但您也可以在主機儲存中檢視從容器生成的檔案。
version: <font>"3" services: postgres: image: postgres:15.1-alpine container_name: postgres environment: - POSTGRES_DB=postgres - POSTGRES_USER=postgres - POSTGRES_PASSWORD=Password12! ports: - "5432:5432" # VOLUMES CONFIG volumes: - ./docker/postgres:/docker-entrypoint-initdb.d
|
其中./docker/postgres是相對於 Docker Compose 檔案的本地資料夾路徑。我們可以將我們的 init 檔案放在那裡,它們將在構建期間自動複製到 Docker 容器,然後在 Docker 容器例項首次執行時執行。這非常簡單且有用,不是嗎?
建立更多資料庫
預設的postgres資料庫外,還將建立blogs和auth兩個資料庫。
我們可以新增一個名為000-create-multiple-postgresql-databases.sh的新指令碼,並在其中放入以下指令碼:
#!/bin/bash
set -e set -u
function create_database() { local database=$1 echo <font>" Creating Database '$database' for '$POSTGRES_USER'" psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" <<-EOSQL CREATE DATABASE $database; GRANT ALL PRIVILEGES ON DATABASE $database TO $POSTGRES_USER; EOSQL }
if [ -n "$POSTGRES_MULTIPLE_DATABASES" ]; then echo "Multiple database creation requested: $POSTGRES_MULTIPLE_DATABASES" for db in $(echo $POSTGRES_MULTIPLE_DATABASES | tr ',' ' '); do create_database $db done echo "Multiple databases created" fi
|
它檢查是否存在POSTGRES_MULTIPLE_DATABASES環境變數。如果有,它會透過用逗號分隔值來獲取資料庫名稱。然後,它會執行create_database函式,該函式會建立一個新資料庫並向透過POSTGRES_USER環境變數提供的使用者授予所有許可權。
現在,如果我們將此檔案放入./docker/postgres資料夾,它將在我們的指令碼之前自動執行。這是因為我們將此資料夾對映到卷,並且指令碼按字母順序執行。
我們需要將 POSTGRES_DB更改為POSTGRES_MULTIPLE_DATABASES:
version: <font>"3" services: postgres: image: postgres:15.1-alpine container_name: postgres environment: # UPDATED TO MULTIPLE DATABASES - POSTGRES_MULTIPLE_DATABASES="postgres,blogs,auth" - POSTGRES_USER=postgres - POSTGRES_PASSWORD=Password12! ports: - "5432:5432" volumes: - ./docker/postgres:/docker-entrypoint-initdb.d
|
使用Web IDE
我們有一個完全設定的資料庫,並可以從我們的應用程式連線到它,但是有一個 IDE 來檢視資料不是很好嗎?
PostgreSQL 有一個不錯的開源 Web IDE,名為pgAdmin。可以將其用作 Docker 映象。讓我們透過擴充套件配置來實現它!
version: <font>"3" services: postgres: image: postgres:15.1-alpine container_name: postgres environment: - POSTGRES_MULTIPLE_DATABASES="postgres,blogs,auth" - POSTGRES_USER=postgres - POSTGRES_PASSWORD=Password12! ports: - "5432:5432" volumes: - ./docker/postgres:/docker-entrypoint-initdb.d
pgadmin: container_name: pgadmin_container image: dpage/pgadmin4 environment: - PGADMIN_DEFAULT_EMAIL=${PGADMIN_DEFAULT_EMAIL:-pgadmin4@pgadmin.org} - PGADMIN_DEFAULT_PASSWORD=${PGADMIN_DEFAULT_PASSWORD:-postgres} - PGADMIN_CONFIG_SERVER_MODE=False - PGADMIN_CONFIG_MASTER_PASSWORD_REQUIRED=False ports: - "${PGADMIN_PORT:-5050}:80" depends_on: - postgres
|
讓我們討論一下那些有點神秘的環境變數設定。
- PGADMIN_DEFAULT_EMAIL和PGADMIN_DEFAULT_PASSWORD - 為 pgAdmin 使用者設定預設憑據。pgAdmin 也可以作為常規服務託管(例如在測試環境中)並具有更高階的使用者設定,但對於本地開發來說單個使用者就足夠了。
- PGADMIN_CONFIG_SERVER_MODE - 確定 pgAdmin 是在伺服器模式(多使用者)還是桌面模式(單使用者)下執行。我們將其設定為 false,這樣就不會提示我們輸入登入憑據。這是一個令人討厭的廢紙,我們要把它去掉。
- PGADMIN_CONFIG_MASTER_PASSWORD_REQUIRED - 控制是否需要主密碼才能訪問已儲存的伺服器定義和其他敏感資訊。透過將其設定為 false,我們可以跳過 pgAdmin 中伺服器詳細資訊的額外密碼保護層。
您可能注意到了一個奇怪的語法:${PGADMIN_DEFAULT_EMAIL: -pgadmin4@pgadmin.org }。此設定意味著,如果在主機環境中定義了PGADMIN_DEFAULT_EMAIL,則使用其值。否則,它將恢復為預設值(在我們的例子中為pgadmin4@pgadmin.org)。
您可以在 shell 中傳遞這樣的變數:
export PGADMIN_DEFAULT_EMAIL=myemail@example.com export PGADMIN_DEFAULT_PASSWORD=securepassword export PGADMIN_PORT=6666 docker-compose up
|
或者在與我們的docker-compose.yml檔案相同的資料夾中定義.env檔案,Docker將自動使用它。PGADMIN_DEFAULT_EMAIL=myemail@example.com PGADMIN_DEFAULT_PASSWORD=securepassword PGADMIN_PORT=6666
|
它對於安全性和在不修改主指令碼的情況下更改變數非常有用。
回到我們的 Docker Compose 配置。如果我們現在啟動容器,我們還會在http://localhost:5050上執行 pgAdmin 。
但是我們不會自動看到任何資料庫
自動發現資料庫
pgAdmin 不會進行任何自動發現。我們可以手動設定連線,但每次清理卷時都需要重複此操作。如果我們想在新環境中清理測試資料(可以透過執行docker compose down -v來完成),這種情況經常發生。
讓我們改變它並自動設定我們的伺服器列表。讓我們首先在新的docker/pgAdmin資料夾中定義servers.json檔案。然後放在那裡:
{ <font>"Servers": { "1": { "Group": "Servers", "Name": "Docker", "Host": "postgres", "Port": 5432, "MaintenanceDB": "postgres", "Username": "postgres", " "Password": "Password12!", "SSLMode": "prefer", "Favorite": true } } }
|
如您所見,我們只是在配置資料庫。如果願意,我們可以透過新增“2”:{ }”等來定義更多內容。
如果你隨機生成密碼(例如在 CI/CD 中),那麼你也可以定義 passfile 並將“Password”: “Password12!“,替換為“PassFile”: “/pgpass”, 。然後你可以保持伺服器設定不變,但只需在passfile中定義資料庫密碼。我們可以將其放在docker/pgAdmin資料夾中並將其放入其中:
postgres:5432:*:postgres:Password12!
讓我們繼續這個較長的路徑來展示完整的設定。我們需要稍微調整一下我們的配置:
version: <font>"3" services: postgres: image: postgres:15.1-alpine container_name: postgres environment: - POSTGRES_MULTIPLE_DATABASES="postgres,blogs,auth" - POSTGRES_USER=postgres - POSTGRES_PASSWORD=Password12! ports: - "5432:5432" volumes: - ./docker/postgres:/docker-entrypoint-initdb.d
pgadmin: container_name: pgadmin_container image: dpage/pgadmin4 environment: - PGADMIN_DEFAULT_EMAIL=${PGADMIN_DEFAULT_EMAIL:-pgadmin4@pgadmin.org} - PGADMIN_DEFAULT_PASSWORD=${PGADMIN_DEFAULT_PASSWORD:-postgres} - PGADMIN_CONFIG_SERVER_MODE=False - PGADMIN_CONFIG_MASTER_PASSWORD_REQUIRED=False ports: - "${PGADMIN_PORT:-5050}:80" depends_on: - postgres user: root entrypoint: /bin/sh -c "chmod 600 /pgpass; /entrypoint.sh;" volumes: - ./docker/pgAdmin/pgpass:/pgpass - ./docker/pgAdmin/servers.json:/pgadmin4/servers.json
|
我們定義了我們的使用者需要是 root,因為我們需要能夠為 passfile 設定適當的許可權。我們可以透過更改入口點來進行這樣的設定:
/bin/sh -c "chmod 600 /pgpass; /entrypoint.sh;"
Entrypoint用於指定啟動容器時執行的命令。這裡我們指的是在執行常規啟動命令之前,執行一個額外的 shell 指令碼,使用chmod函式設定
適當的pgpass許可權。
我們還對映卷以將pgpass和servers.json放入適當的資料夾中。如您所見,我們還可以對映特定檔案,而不僅僅是目錄。
現在,如果我們執行:
docker compose up
我們應該獲得帶有預配置資料庫的 pgAdmin。太棒了!