【譯】在幾秒鐘內為你的開發(fā)環(huán)境創(chuàng)建一個私有 PostgreSQL 數(shù)據(jù)庫

image

很多開發(fā)者在開始一個新項目的時候,通常會使用 JSON,CSV 或者其他 Flat File 來模擬真實存放在數(shù)據(jù)庫中的數(shù)據(jù)。這是因為他們總是在沒有真實的數(shù)據(jù)庫環(huán)境限制和是否需要自己創(chuàng)建模擬數(shù)據(jù)庫之間左右為難。既然這樣,為什么不使用 Docker Compose 定義一個可以在幾秒鐘內創(chuàng)建、銷毀和重新創(chuàng)建的 PostgreSQL 數(shù)據(jù)庫和監(jiān)視工具?

image

正確創(chuàng)建配置兩個容器的 Docker 命令過于冗長。而使用 Docker Compose,你只需要記住up命令和down命令!

Up命令將創(chuàng)建指定版本的 PostgreSQL 數(shù)據(jù)庫和一個 GUI 管理工具。 Down命令會將其關閉并刪除。

基于私有容器的數(shù)據(jù)庫的好處

  • 不同版本的 PostgreSQL 在行為和功能上存在差異,因此開發(fā)人員應針對一個數(shù)據(jù)庫版本進行長期開發(fā)。你可以選擇的一個版本是 9.6.12,另一個可以是 12.4。
  • 大多數(shù)程序員都不是數(shù)據(jù)庫管理員或 SQL 專家??梢暬ぞ呖梢宰屗麄冎庇^地驗證其代碼的運行效果并支持手動修改數(shù)據(jù)。
  • 項目的不同階段需要不同類型的存儲方案。 在項目早期,非持久型數(shù)據(jù)庫可以最大程度地減少麻煩。 在項目的后期階段,持久型數(shù)據(jù)庫提供了更實際的方案。
Create and recreate a database with simple commands

建立開發(fā)堆棧

下面所展示的這份 docker-compose.yml 文件定義了一個運行特定版本 PostgreSQL 和 pgAdmin 4(Postgres 最常用的管理工具)的 PostgreSQL 容器。該文件的內容值得我們詳細的探討。

version: "3.8"
services:
  postgres:
    image: postgres:9.6.12-alpine
    container_name: some-postgres
    volumes:
      - "~/Documents/docker_pgsql_init:/docker-entrypoint-initdb.d"
      - "~/Documents/docker_pgsql_volume:/var/lib/postgresql/data"
    ports:
      - 5432:5432
    environment:
      - POSTGRES_PASSWORD=mysecret
    deploy:
      restart_policy:
        condition: on-failure
        max_attempts: 3

  pgadmin:
    image: dpage/pgadmin4
    container_name: some-pgadmin
    volumes:
      - ${PWD}/servers.json:/pgadmin4/servers.json
    ports:
      - 8080:80
    environment:
      - PGADMIN_DEFAULT_EMAIL=user@domain.com
      - PGADMIN_DEFAULT_PASSWORD=admin
    deploy:
      restart_policy:
        condition: on-failure
        max_attempts: 3

Docker Compose 的文件結構

該文件定義了兩個要創(chuàng)建的“服務”:Postgres 和 pgAdmin。 每個服務都包含一個從 Docker Hub 拉取的容器。 Postgres 和 pgAdmin 將分別開放 5432 端口和 8080 端口。將你寫的任何程序指向主機名“ localhost”,然后用瀏覽器訪問http://localhost:8080 即可訪問 pgAdmin。

繼續(xù)閱讀有關如何將 pgAdmin 指向 Postgres 的說明。

PostgreSQL 的版本

在定義 Postgres 容器的這一行中,你需要準確指定所需的 Postgres 版本。在這里,version 是一個標簽,而9.6.12-alpine就是我們示例中的版本。點擊這里查看其他可用的版本

Postgres 的存儲

上面的docker-compose.yml 文件為 Postgres 指定了兩個映射卷。 這兩個映射將使 Postgres 可以訪問你計算機上的目錄。

  1. 被映射到/docker-entrypoint-initdb.d的文件夾包含了初始化 Postgres 將會用到的 SQL 文件。將所需的 SQL 文件和 Shell 腳本放在該目錄中,它們將會按字母順序自動執(zhí)行。
  2. 被映射到/var/lib/postgresql/data的文件夾存放了數(shù)據(jù)庫持久化存儲所需要的真實文件。

當 Postgres 啟動時,他的運行流程如下圖所示。 如果數(shù)據(jù)庫中沒有數(shù)據(jù),那么它將執(zhí)行被映射到/docker-entrypoint-initdb.d目錄中的每個 SQL 文件和 Shell 腳本(按字母順序)。如果被映射到 /var/lib/postgresql/data的文件夾中有數(shù)據(jù),那么它將會忽略掉這些文件。

image

你是否需要掛載這兩個目錄?這個得視情況而定。下表描述了通過分別映射 Postgres 的兩個卷中的一個而預期的行為。

image

我的建議是對這兩個文件目錄都做映射。如果你不想再初始化你的數(shù)據(jù)庫,你可以從 init 目錄中刪除文件。你也可以在你的計算機上刪除任何可能已經持久化的數(shù)據(jù)(當你下一次運行docker-compose up命令時,Docker 將會在其位置重新創(chuàng)建一個空文件夾)。

專業(yè)提示:你可以將 CSV 文件放在計算機的 init 文件夾中,然后在 init 目錄中通過適當?shù)?SQL 命令將 CSV 文件中的數(shù)據(jù)填充到數(shù)據(jù)表中。

CREATE TABLE Employee(id, first_name, last_name, salary);
COPY Employee FROM '/docker-entrypoint-initdb.d/emp.csv'
    WITH (FORMAT CSV, HEADER);

pgAdmin 存儲

image

盡管 pgAdmin 只是一個用于查看和配置數(shù)據(jù)庫的工具,但必須配置其與數(shù)據(jù)庫的連接。 這可以通過可視化工具中的add server指令完成。這里需要注意的是,主機名(the hostname)是我們在 YML 文件中配置的 container_name 這一參數(shù)的名稱,即 some-postgres。同樣地,密碼也已經在 YML 文件中指定了,即 mysecret。

另一種方法是通過在 JSON 文件中指定這些配置(除了密碼之外的所有配置),通過這種方式可以免去大量的單擊和輸入操作。為了避免手動配置 pgAdmin 連接到 Postgres,我們需要將該 JSON 文件映射到容器的/pgadmin4/servers.json上(在示例 YML 文件中的第 22 行)。

設置文件可以指定 pgAdmin 和 Postgres 之間的多個連接(以不同用戶的身份連接或者連接到多個不同的數(shù)據(jù)庫)。下面是只有一個數(shù)據(jù)庫連接的示例。

{
    "Servers": {
        "1": {
            "Name": "my-postgres",
            "Group": "Servers",
            "Port": 5432,
            "Username": "postgres",
            "Host": "some-postgres",
            "SSLMode": "prefer",
            "MaintenanceDB": "postgres"
        }
    }
}

網絡

container_name 參數(shù)僅僅只表示一個名字。但是 pgAdmin 將使用這個名稱訪問 5432 端口上的數(shù)據(jù)庫。原因如下圖所示。這兩個容器通過私有網絡相互連接,因此可以通過它們的主機名(容器名)也就是 some-postgressome-pgadmin 相互訪問。然而,你的主機(也就是你的計算機和 web 瀏覽器)只能訪問容器對外暴露的 5432 端口和 8080 端口,因此你可以通過 localhost:5432localhost:8080 訪問它們。

image

內部網絡的名稱可以在 compose 文件中指定,但是為一個從未被代碼引用的網絡命名沒有任何價值!如果你還是好奇,可以隨時查看你的私人及臨時網絡的名稱。在下面的代碼片段中,我從桌面運行了 Docker Compose,因此將該網絡命名為desktop_default。

$ docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
23a6be9b8021        bridge              bridge              local
49a120440f88        desktop_default     bridge              local
44a949b56fa7        host                host                local
3892b16dca2d        none                null                local

Docker 和 docker-compose 命令

在這里,我必須承認我在介紹中過分簡化了命令,但只是稍微簡化了一點。

為了啟動容器,可以使用 docker-compose up -d。-d 參數(shù)指定這是一個 detached 模式,它將會在后臺運行,并且不會影響你在命令提示符中執(zhí)行其他命令。

$ docker-compose up -d
Creating network "desktop_default" with the default driver
Creating some-postgres ... done
Creating some-pgadmin  ... done
$

為了關閉并刪除容器,你可以使用 docker-compose down -v-v 參數(shù)表示刪除容器在運行時使用的卷。這個不會刪除容器映射到計算機上的目錄。

$ docker-compose down -v
Stopping some-pgadmin  ... done
Stopping some-postgres ... done
Removing some-pgadmin  ... done
Removing some-postgres ... done
Removing network desktop_default

隨著時間的推移,如果不使用 -v 標志,就會累積不必要的卷。你可以使用 docker volume ls 來驗證這一點。

如果要調試一個沒有正確啟動的容器,請使用 docker logs [container_name]。例如,由于 init 目錄中的一個 SQL 文件中出現(xiàn)錯誤,數(shù)據(jù)庫可能無法正確初始化。通過執(zhí)行 docker logs some-postgres 命令,可以生成容器啟動時記錄的日志,通過對該日志的查閱,我在一個特殊命名的 SQL 文件中發(fā)現(xiàn)一個錯誤:

/usr/local/bin/docker-entrypoint.sh: running /docker-entrypoint-initdb.d/broken.sql
ERROR:  syntax error at end of input at character 34
STATEMENT:  CREATE TABLE Songs(id, name, year
psql:/docker-entrypoint-initdb.d/broken.sql:1: ERROR:  syntax error at end of input
LINE 1: CREATE TABLE Song(id, name, year

日志告訴我在 broken.sql 文件的第 1 行有一個錯誤。該命令缺少閉括號和分號。我可以修復這個錯誤,并使用 downup 來驗證。


使用 Python

使用 localhost 作為 YML 文件中指定的主機名和密碼,連接到數(shù)據(jù)庫很容易。

import psycopg2

# connect to DB
conn = psycopg2.connect(host="localhost", dbname="postgres", user="postgres",
    password="mysecret")
cursor = conn.cursor()

# execute SQL commands in SQL file
cursor.execute(open("emp.sql", "r").read())

# retrieve data from the database
cursor.execute("SELECT * FROM Employee")
print(cursor.fetchall())

使用 pgAdmin

簡單的訪問 http://localhost:8080 即可進入登錄界面,使用你在 docker-compose.yml 文件中定義的用戶名和密碼登錄即可(在我們的示例中是 user@domain.comadmin)。

image

如果你使用的是本文之前討論的 servers.json 文件來指定連接細節(jié),你將會在展開用戶界面左側的導航樹時,收到系統(tǒng)要求你輸入 Postgres 數(shù)據(jù)庫的密碼的提示。在我們示例的 docker-compose.yml 文件中,這個密碼是 mysecret 。如果你并沒有創(chuàng)建 servers.json 文件或文件中有錯誤,你就必須手動添加服務器。

image

現(xiàn)在,你應該能夠查看和操作數(shù)據(jù)庫了。

image

進入 PSQL

有時候,開發(fā)者需要一個熟悉的命令行。 Docker 使得訪問 PSQL 和執(zhí)行高級用戶命令等操作變得更加容易。 執(zhí)行下面的命令進入 PSQL 命令行。

image

連接后,你就可以執(zhí)行所有 PSQL 命令,例如,輸入 \i 用于導入外部數(shù)據(jù)庫,輸入 \dt 顯示數(shù)據(jù)表的描述,輸入 \df 顯示函數(shù)的描述。想要退出,可以使用 \q 命令。

$ docker exec -it some-postgres psql -U postgres

psql (9.6.12)
Type "help" for help.

postgres=# \dt
List of relations
Schema |     Name     | Type  |  Owner
--------+--------------+-------+----------
public | peak         | table | postgres
public | climb        | table | postgres
public | climber      | table | postgres

pgAdmin 的替代品

Adminer is a much simpler interface

pgAdmin 是 PostgreSQL 最常見的 GUI 管理工具,但我們還有其他選擇。 Adminer 的使用更加簡單,并且你可能已經擁有使用它的經驗了,因為它支持多種風格的 SQL。 如果你是剛開始使用 PostgreSQL 或者只有非常簡單的需求,那么它可能是一個更合適你的工具。

在登錄界面上,設置主機名為 some-postgres ,密碼為mysecret。

image

要在你的環(huán)境中用 Adminer 替換 pgAdmin,你需要在 docker-compose.yml 中替換幾行有關 pgAdmin 容器的定義。

  adminer:
    image: adminer
    container_name: some-adminer
    ports:
      - 8080:8080
    deploy:
      restart_policy:
        condition: on-failure
        max_attempts: 3

引用

所有優(yōu)秀的開發(fā)者都依賴于產品文檔和其他人員的經驗。 這是我在創(chuàng)建工作流程和編寫本文時引用的來源。

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容