Docker: Docker Compose คือ ?

Somprasong Damyos
3 min readFeb 13, 2017

--

Docker Compose

ต้องบอกก่อนว่า Docker นั้นสามารถใช้ Docker Engine จัดการ container แต่ละตัวโดยใช้คำสั่ง docker run|start|stop|rm กับสร้าง imageโดยใช้ docker build ได้ดีอยู่แล้ว แต่ให้ลองนึกว่าว่าถ้าในโปรเจคของเรานี่ต้องการใช้งานหลายๆ containers ทำงานร่วมกัน เราจะต้องมา docker run ทีละตัว ไหนจะต้องทำให้ link มันเข้าหากัน หรือถ้าจะ restart หรือ build ใหม่ ก็ทำเขียนคำสั่งหลายบรรทัดแน่นอน แค่คิดก็เหนื่อยแล้วใช่มั้ย

ซึ่งปัญหาเหล่านั้นเราสามารใช้ Docker Compose สั่ง start|stop|restart|log|build โดยใช้คำสั่งเพิ่งแค่บรรทัดเดียว ในจัดการหลายๆ containers พร้อมๆ กันได้ เพียงแค่เขียนคำสั่งต่างๆ เอาไว้ในไฟล์ docker-compose.yml ซึ่งปัจจุบันรูปแบบไฟล์จะอยู่ที่ Version 3 แล้วสั่งใช้งานผ่านคำสั่ง docker-compose

ลองเลยดีกว่า

เริ่มจากง่ายๆ ก่อน ลองเอาโปรเจคเดิมตอนที่ทำ Dockerizing a Node.js Web App มารันผ่าน Docker Compose ดีกว่า

  1. สร้างไฟล์ docker-compose.yml ไว้ในโปรเจคโฟลเดอร์ และใส่โค้ดดังนี้
version: '3'
services:
web:
build: .
ports:
- "3000:3000"
volumes:
- ./app:/nodeapp
redis:
image: "redis:3.0"

คำอธิบาย
version คือ การระบุว่าจะใช้รูป Compose file เวอร์ชันไหน ดูเพิ่มเติมได้จาก Docs
services จะมีกี่ container ที่ต้องการใช้เอามาระบุตรงนี้ โดยในตัวอย่างจะมี 2 services คือ web และ redis
build คือ การบอกว่าให้ใช้ image ที่สร้างจาก Dockerfile
ports เป็นการทำ port mapping ระหว่าง host กับ container เหมือนตอน docker run -p
volumes คือ การ mount โฟลเดอร์ app ของ host เข้ากับ /nodeapp ข้างใน container เพื่อให้เราสามารถแก้ไขโค้ดได้
image คือ การใช้ image จาก Docker Hub registry

หมายเหตุ เนื่องจากเราใช้ volumes ซึ่งมันจะ mount โฟลเดอร์ app ของ host เข้ากับ /nodeapp ข้างใน container มันจะเอาทุกอย่างจาก app ไปทับ nodeapp ทั้งหมด (ที่ Dockerfile สร้างขึ้นมา)จะต้องสั่งรัน npm install ใน app ก่อน จึงจะทำงานได้

2. สั่ง start จากโปรเจคโฟลเดอร์

$ docker-compose upCreating network "dockerizevoteapp_default" with the default driver
Building web...
Pulling redis (redis:3.0)...
Creating dockerizevoteapp_redis_1
Creating dockerizevoteapp_web_1
Attaching to dockerizevoteapp_redis_1, dockerizevoteapp_web_1
redis_1 | Running in standalone mode Port: 6379
web_1 | Server started

3. เข้าใช้งาน http://192.168.99.100:3000 จาก browser จะพบว่าโปรแกรมกำลังทำงานอยู่

4. ลองแก้ไขไฟล์ app/views/index.ejs โดยเพิ่มคำว่า “Edited from host” และลอง Refresh ดูจะพบว่าหน้าเวบของเรามีคำว่า “Edited from host” เพิ่มขึ้นมา

คำสั่งอื่นๆ

  • ถ้าต้องการให้ทำงานใน Detached Mode ก็ให้ใส่ -d flag เพิ่มเข้าไป และสามารถดูว่ามี services อะไรที่กำลังรันอยู่บ้างจาก docker-compose ps
$ docker-compose up -d
Creating network "dockerizevoteapp_default" with the default driver
Creating dockerizevoteapp_redis_1
Creating dockerizevoteapp_web_1
$ docker-compose ps
Name Command State Ports
------------------------------------------------------------------------------------------
dockerizevoteapp_redis_1 docker-entrypoint.sh redis ... Up 6379/tcp
dockerizevoteapp_web_1 node app.js Up 0.0.0.0:3000->3000/tcp
  • วิธีดู log การทำงานใช้ docker-compose log และถ้าต้องการติดตาม log ใช้ -f flag เพิ่มเข้าไป
  • หรือจะรัน service ใหม่แค่ตัวเดียวก็จะใช้docker-compose run ตัวอย่างเพื่อจะดูว่าใน service ชื่อ redis มี environment variables อะไรบ้าง
$ docker-compose run redis env
HOSTNAME=daa1bc37ac01
HOME=/root
REDIS_DOWNLOAD_SHA1=e56b4b7e033ae8dbf311f9191cf6fdf3ae974d1c
TERM=xterm
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
REDIS_DOWNLOAD_URL=http://download.redis.io/releases/redis-3.0.7.tar.gz
REDIS_VERSION=3.0.7
GOSU_VERSION=1.7
PWD=/data
  • กรณีที่รันกับคำสั่ง docker-compose up -dและต้องการจะหยุดการทำงานของ services ใช้คำสั่ง docker-compose stop
  • และถ้าต้องการจะลบ containers ที่สั่งหยุดการทำงานไปใช้ docker-compose rm --all
  • ถ้าไม่ต้องการจะใช้งาน และลบ containers ทั้งหมดทิ้ง ใช้คำสั่ง down และใส่ --volumes เพื่อลบ volume ที่สร้างไว้ทั้งหมด ที่ประกาศไว้ใน ‘volumes’ section
$ docker-compose down --volumes
  • ถ้ามีการแก้ไข Dockerfile และสั่ง docker-compose up เราจะไม่ได้ image ใหม่ตามที่แก้ไขไว้ ต้องสั่ง docker-compose build ใหม่ก่อน หรือใช้ docker-compose up --build ก็ได้

มาลองสร้าง Compose file ที่ซับซ้อนขึ้นมาอีก

เรามาลองติดตั้ง WordPress.org ดีกว่า ซึ่งถ้าอ่านจากคู่มือการติดตั้ง จะเห็นว่าต้องติดตั้งหลายอย่างมาก ตั้งแต่ PHP, MySQL/MiriaDB, Web Server และ phpMyAdmin ต้องดาวน์โหลด WordPress มาติดตั้ง ตั้งค่า configuration ต่างๆ ต้องนำเข้าฐานข้อมูลอีก กว่าจะใช้งานได้ เหนื่อยแน่ๆ

เรามาลองเอาทั้งหมดนั้นมาใส่ไว้ใน Compose file แล้วสั่งรันผ่าน docker-compose up -d ดีกว่า

  1. สร้างไฟล์ docker-compose.yml ไว้ในโฟล์เดอร์ชื่อ ‘dc-wordpress’
$ mkdir dc-wordpress
$ cd dc-wordpress/
$ touch docker-compose.yml

2. ใส่คำสั่งข้างล่างลงใน docker-compose.yml

version: '3'services:
wp_db:
image: mariadb:10.1
volumes:
- db_data:/var/lib/mysql
restart: always
environment:
MYSQL_ROOT_PASSWORD: wordpress
MYSQL_DATABASE: wordpress
MYSQL_USER: wordpress
MYSQL_PASSWORD: wordpress
wp:
depends_on:
- wp_db
image: wordpress:latest
ports:
- "8080:80"
restart: always
environment:
WORDPRESS_DB_HOST: wp_db:3306
WORDPRESS_DB_PASSWORD: wordpress
pma:
depends_on:
- wp_db
image: phpmyadmin/phpmyadmin
links:
- wp_db:db
ports:
- "8181:80"
restart: always
environment:
MYSQL_ROOT_PASSWORD: wordpress
volumes:
db_data:
driver: local

คำอธิบาย
มี services อยู่ทั้งหมด 3ตัว
1. wp_db คือ ระบบฐานข้อมูลจะใช้ MariaDB version 10.1 และมีการกำหนดค่า environment ที่ต้องใช้งาน 4 ตัว
2. wp คือ ตัว WordPress เนื่องจาก image ของ WordPress ที่ใช้จะเอาตัวล่าสุดมาจึงใส่ tag เป็น latest ซึ่งถ้าไปดูใน Dockerfile นี้ จะพบว่าตัวมันจะติดตั้ง PHP พร้อมทั้งติดตั้ง WordPress มาให้เรียบร้อยแล้ว
3. pma คือ phpMyAdmin เอาไว้จัดการกับระบบฐานข้อมูล สังเกตว่าไม่ได้ใส่ tag ไว้ ดังนั้น Docker Compose จะเอาจาก tag latest มาให้เสมอ
ส่วนคำสั่งอื่นๆ
- restart: alway คือ กำหนดให้ service นั้น restart ตัวเองอัตโนมัติเมื่อเกิดข้อผิดพลาดที่ทำให้โปรแกรมหยุดการทำงานไป หรือสั่งให้เริ่มต้นทำงานอัตโนมัติเมื่อเปิดเครื่องขึ้นมาใหม่
- volumes สังเกตว่าจะมี volumes 2 ตำแหน่ง ซึ่งถ้าอยู่ภายในชื่อ service แต่ละตัวก็คือการเชื่อม volume เหมือน docker run -v แต่ถ้าอยู่ในระดับเดียวกับ services: มันคือการสร้าง volume ขึ้นมา

- depend_on คือสั่งให้ service นั้นๆ เริ่มต้นการทำงานหลังจาก service ที่ depend on อยู่เริ่มต้นการทำงานเสร็จแล้ว
- links คือการผูก service เข้าด้วยกัน รูปแบบ Sevice name:Alias name โดยจะทำให้ service นั้นสามารถเรียกใช้งาน service ที่ link ได้ทั้งจากชื่อ Service name และ Alias name และเนื่องจาก service “pma” นั้น ต้องการชื่อของระบบฐานข้อมูลว่า “db” แต่ service ของระบบฐานข้อมูลเราตั้งชื่อว่า wp_db ทำให้ไม่สามารถเรียกใช้งานได้ จึงต้องใช้ link สร้าง alias name จาก wp_db เป็น db ก่อน

3. สั่งเริ่มต้นการทำงานทุกอย่างในคำสั่งสั่งเดียว

$ docker-compose up -d
Creating network "dcwordpress_default" with the default driver
Creating volume "dcwordpress_db_data" with default driver
Pulling wp_db (mariadb:10.1)...
Pulling pma (phpmyadmin/phpmyadmin:latest)...
Pulling wp (wordpress:latest)...
Creating dcwordpress_wp_db_1
Creating dcwordpress_wp_1
Creating dcwordpress_pma_1

เริ่มต้นการทำงานจะเห็นว่ามีการสร้าง network ชื่อ “dcwordpress_default” ขึ้นมา ซึ่ง services ทุกตัวจะรันอยู่บน network นี้ และจะถูกเชื่อมเข้าด้วยกัน

สรุป

จะเห็นได้ว่าถ้าในโปรเจคของเราต้องใช้งาน containers หลายๆ ตัวร่วม Docker Compose จะช่วยให้เราจัดการปกับ containers เหล่านั้นได้ง่าย และสะดวกขึ้น ไม่ว่าจะเป็นการ start|stop|restart|log|build โดยใช้คำสั่งแค่บรรทัดเดียว

--

--