เวลาที่เราใช้ PostgreSQL ใน Docker container เราสามารถกำหนดตัวแปรสำหรับสร้าง USER, PASSWORD, DATABASE ได้เลย
ตัวอย่าง ไฟล์ docker-compose.yml
version: '3'
services:
db:
image: postgres
restart: always
environment:
POSTGRES_DB: kong
POSTGRES_USER: kong
POSTGRES_PASSWORD: kong
volumes:
- ./pg_data:/var/lib/postgresql/dataจากตัวอย่างไฟล์ docker-compose.yml ด้านบน จะได้ User / Password / Database มา 1 ชุด สามารถแสดง user ได้ด้วยคำสั่ง
docker-compose exec db psql -U kong -c '\du'

ในกรณีที่เราอยากได้ USER, PASSWORD, DATABASE มากกว่า 1 ตั้งแต่แรก เราสามารถที่จะสร้างไฟล์ สำหรับการเริ่มต้นทำงานของ PostgreSQL ใน Docker container ได้ โดยเขียนไฟล์สำหรับสร้าง USER, PASSWORD, DATABASE ไว้ที่ /docker-entrypoint-initdb.d
ตัวอย่างไฟล์ /docker-entrypoint-initdb.d/init-user-db.sh
#!/bin/sh
set -e
psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" <<-EOSQL
CREATE USER docker;
CREATE DATABASE docker;
GRANT ALL PRIVILEGES ON DATABASE docker TO docker;
EOSQLจากนั้นแก้ Permission ของไฟล์ chmod +x init-user-db.sh และเพิ่มการแมปไฟล์เข้าไปใน container ทื่ docker-compose.yml
version: '3'
services:
db:
image: postgres
restart: always
environment:
POSTGRES_DB: kong
POSTGRES_USER: kong
POSTGRES_PASSWORD: kong
volumes:
- ./pg_data:/var/lib/postgresql/data
- ./init-user-db.sh:/docker-entrypoint-initdb.d/init-user-db.shถ้าสั่ง docker-compose up -d เพื่อรัน PostgreSQL สิ่งที่คาดว่าจะได้เพิ่มมาคือ
Database = kong, Username = kong, Password = kong
Database = docker, Username = dockerแต่ว่า ในกรณีนี้ จะได้แค่
Database = kong, Username = kong, Password = kongเท่าเดิม...
เพราะว่า PostgreSQL มองว่ามีไฟล์ database อยู่แล้ว จะไม่รัน initdb ใหม่ ถ้าอยากได้ 2 user รวมที่อยู่ใน init-user-db.sh ด้วย ต้องลบ pg_data ทิ้ง
docker-compose down
rm -rf pg_data
docker-compose up -d
docker-compose exec db psql -U kong -c '\du'
จะเห็นว่า วิธีนี้ มันทำให้เราต้องลบ pg_data ออกก่อนถึงจะใช้ได้
ในกรณีที่ เราอยากได้ User / Password / Database เพิ่มเติม หลังจากที่รัน PostgreSQL ไปแล้ว มีหลายวิธี เช่น
- ใช้
docker execคำสั่งbash/shก่อน จากนั้นรันคำสั่งpsqlเพื่อเข้าไปในpsql shellแล้วค่อยสร้างUser / Password / Database - ใช้
docker execคำสั่งpsqlโดยตรง เพื่อเข้าไปสร้างUser / Password / Database - ใช้
docker execคำสั่งpsqlพร้อมกับส่งsqlเข้าไปให้คำสั่งpsql
หลายวิธีด้านบน สามารถทำได้ผลเหมือน ๆ กัน แต่จะใช้หลายคำสั่งในการทำกว่าจะสร้าง User / Password / Database เพิ่มได้ ผมมีเหตุการณ์ ที่อยากจะรันเพียง 1 คำสั่ง เพื่อให้สามารถสร้าง User / Password / Database สำหรับ PostgreSQL ที่รันอยู่ได้
จริง ๆ จะว่าไป มันก็ไม่ได้เป็น 1 คำสั่งซะทีเดียว แต่เป็นการเขียน script ที่มีความยืดหยุ่นมากพอ ที่จะทำให้การรัน script เพียง 1 คำสั่ง สามารถได้สิ่งที่ต้องการครบ คือการสั่ง docker exec คำสั่งในไฟล์ script
ตัวอย่างไฟล์ create-user-db.sh
#!/bin/sh
set -x
POSTGRES="psql --username ${POSTGRES_USER}"
$POSTGRES <<-SQL
CREATE USER ${DB_USER} WITH CREATEDB PASSWORD '${DB_PASSWORD}';
CREATE DATABASE ${DB_NAME} OWNER ${DB_USER};
SQLจาก script ด้านบน เราสามารถใช้งานร่วมกันกับ docker -e ที่ใช้ตั้งค่า environment variable ได้
ตัวอย่างการใช้งาน
ต้องมี db รันอยู่ก่อนหน้านี้แล้ว
docker-compose exec -T \
-e DB_USER=hello \
-e DB_PASSWORD=password \
-e DB_NAME=world \
db sh 2>/dev/null < create-user-db.sh
จะเห็นว่า วิธีนี้ ทำให้เราไม่ต้องลบ pg_data ออกก่อน ไม่ต้อง รันคำสั่ง docker exec หลาย ๆ คำสั่ง
สำหรับ script ที่สมบูรณ์ สวยกว่าข้างบน แก้ create-user-db.sh ตามนี้
#!/bin/sh
# https://github.com/docker-library/postgres/issues/151
set -x
POSTGRES="psql --username ${POSTGRES_USER}"
echo "Before"
echo "======"
$POSTGRES <<-SQL
\du
SQL
echo -n "[*] Creating database role: ${DB_USER}... "
$POSTGRES <<-SQL
CREATE USER ${DB_USER} WITH CREATEDB PASSWORD '${DB_PASSWORD}';
SQL
echo -n "[*] Creating database ${DB_NAME}... "
$POSTGRES <<-SQL
CREATE DATABASE ${DB_NAME} OWNER ${DB_USER};
SQL
echo
echo "After"
echo "====="
$POSTGRES <<-SQL
\du
SQL
จากนั้นลองสร้าง User / Database / Password เพิ่ม
docker-compose exec -T \
-e DB_USER=dev \
-e DB_PASSWORD=devpass \
-e DB_NAME=dev_db \
db sh 2>/dev/null < create-user-db.sh