เวลาที่เราใช้ 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