EP4 Docker ทีเล่น ทีจริง

Supphachoke Suntiwichaya
NECTEC
Published in
5 min readOct 2, 2017
ภาพจาก: https://i0.wp.com/blog.docker.com/media/2015/04/docker-turtles-communication.jpg?ssl=1

เว้นช่วงไปนาน มีกิจกรรมให้ทำเยอะไปหน่อย สำหรับ EP4 ยังคงเป็นการปูพื้นสำหรับคนที่สนใจนำ Docker ไปใช้งาน Dev อย่างจริงจังบนเครื่องของตัวเอง หรือ บน server กลางของบริษัท EP นี้เป็นการพูดถึงการเชื่อมต่อ Container ตั้งแต่สองตัวขึ้นไปเข้าด้วยกัน เช่น มีหน้าเว็บ และ ฐานข้อมูล เป็นต้น

การเชื่อมต่อ Container เข้าด้วยก็เหมือนๆ กับการเชื่อมต่อ vm หรือ computer เข้าด้วยนั้นแหละครับ คือมี network เข้ามาเกี่ยวข้องบน docker ก็ถูกออกแบบมาให้รองรับเรื่องพวกนี้แล้วเช่นกัน ซึ่งมีทั้งแบบ standalone และ แบบข้ามเครื่อง แต่พื้นฐานใน EP นี้ขอยกตัวอย่างแบบง่ายๆ คือ แบบ standalone ส่วนใครสนใจนำไปประยุกต์ใช้ต่อก็สามารถเข้าไปอ่านกันได้ที่ https://docs.docker.com/engine/userguide/networking/

Docker Network พื้นฐาน

การจัดการ docker network บนเครื่องของเราก็ไม่ได้ยุ่งยากอะไรลองพิมพ์คำสั่ง

$ docker network help

ก็จะมีคำสั่งให้เราใช้อยู่ไม่กี่คำสั่งมาเริ่มกันเลย อ้อ!! แนะนำสำหรับการทดลองรอบนี้ว่า เราควรเปิด shell สำหรับใช้งานสัก 3–4 shell ถ้าใครใช้ tmux ก็จะง่ายหน่อย

เปิด shell สัก 3–4 shell

Run Container ค้างไว้สัก 2 Container อย่าลืมตั้งชื่อให้ด้วยนะครับ

$ docker run --rm -it --name somsri  --hostname somsri alpine sh --login$ docker run --rm -it --name somchai  --hostname somchai alpine sh --login

ตัวอย่างผมสร้าง somsri กับ somchai ขึ้นมา ผมใส่ --login ให้ sh ด้วยเพื่อให้ prompt แสดงชื่อ host ดังรูป ลอง ping ด้วยชื่อกันดูครับ

somsri:/# ping somchaiping: bad address 'somchai'

แล้วถ้า ping ด้วย ip ละ ? ลองตรวจสอบ ip ของทั้งสองดู

somsri

somsri:/# ifconfig eth0

somchai

somchai:/# ifconfig eth0

คราวนี้ลอง ping ไปยัง ip จากเครื่อง somsri ไปยัง somchai

somsri:/# ping -c3 172.17.0.3

พบว่าเราสามารถใช้ ip ในการเชื่อมต่อกันได้ระหว่าง container แต่การใช้งานจริงนั้น เรามีการสร้างและลบ container อยู่บ่อยๆ ถ้าสร้าง service ขึ้นมาเราต้องคอยตามแก้ ip กันวุ่นวาย มันมีวิธีที่ง่ายกว่า คือการสร้าง network ขึ้นมาเป็น เช่น กลุ่ม service vdo api เราก็สร้าง network ชื่อ vdo_api กลุ่ม web เราก็สร้าง network web_net เป็นต้น

การสร้าง network

ลองมาสร้าง network เพื่อเชื่อมต่อ somsri กับ somchai โดยใช้ชื่อว่า som_net ดู

$ docker network create som_net

วิธีตรวจสอบดูว่า network ที่เราสร้างมา หรือ ที่มีในเครื่องเรามี network อะไรบ้าง ใช้คำสั่ง

$ docker network lsNETWORK ID         NAME                DRIVER              SCOPE7f65debd0374       som_net             bridge              local

ลองตรวจสอบดูว่า som_net ได้ subnet อะไรมา

$ docker network inspect som_net"Subnet": "172.27.0.0/16"

คราวนี้ก็ connect somsri และ somchai เข้ากับ network ที่สร้างขึ้นมา

$ docker network connect som_net somsri$ docker network connect som_net somchai

ถ้าเราลอง ifconfig ดูก็จะมี eth1 เพิ่มขึ้นมาทั้งสอง container คราวนี้ลอง ping กันโดยใช้ชื่อดู

จริงๆ วิธีแรกที่ ping โดยใช้ ip นั้นเราสามารถตั้งค่าชื่อ hostname ใน /etc/hosts ก็ได้เช่นกันแต่อย่างที่บอกว่าถ้ามีการสร้างลบ container อยู่บ่อยๆ โอกาสที่ ip จะเปลี่ยนก็มีสูง แต่ถ้าใช้ docker network ip จะเปลี่ยนไปยังไงเราก็ใช้ชื่อ container ติดต่อกันได้ตลอด

ตอนนี้เรารู้วิธี connect container ที่ run อยู่แล้ว เข้ามาใช้ network ที่สร้างไว้ได้แล้ว แต่ถ้าเราต้องการ connect ตั้งแต่ต้นละทำยังไง ? ก็ง่ายๆ ไม่มีอะไรยุ่งยาก

  1. create network
  2. run container โดยใส่ --net เข้าไปด้วย
$ docker run --rm -it --name somsri  --hostname somsri --net som_net alpine sh --login$ docker run --rm -it --name somchai  --hostname somchai --net som_net alpine sh --login

ไม่ยากเลยใช่ไหมครับ docker network เบื้องต้นก็มีแค่นี้เอง ส่วนขั้นสูงกว่านี้ เช่นการทำ overlay ข้ามเครื่อง ก็สามารถเข้าไปศึกษาต่อกันได้

ทำโจทย์

มาทำโจทย์ง่ายๆ เป็นการทบทวนกัน มาทำเว็บโดยมี 3 Containers และ 1 network ดังนี้

  1. network ชื่อ net01
  2. Nginx => port 8222
  3. php-fpm
  4. MariaDB

** run nginx ลองกลับไปอ่าน EP3 กันดูเพื่อทบทวนนะครับ

** วิธีทำเป็นการทดสอบเท่านั้นนะครับถ้าจะนำไปใช้จริงแนะนำให้ทำ Dockerfile แทน

สร้าง network

$ docker network create net01

Run PHP fpm container

ผมเลือก run php fpm container ก่อนแล้วค่อย run nginx เข้ามา connect

$ docker run -d --name php --hostname php --net net01 -v `pwd`/web:/var/www/html php:rc-fpm

ถ้าเราเข้าไปศึกษาที่ docker hub จะพบว่า php fpm จะ run ที่ port 9000 และ source code default จะเก็บไว้ที่ /var/www/html เมื่อเรารู้ข้อมูลเราก็เตรียมไว้สร้าง config ของ nginx ต่อไป

Run Nginx container

$ docker run -d --name nginx --hostname nginx --net net01 -p 8222:80 -v `pwd`/web:/var/www/html nginx

copy config ของ nginx ออกมาเพื่อแก้ไข

$ docker cp nginx:/etc/nginx/conf.d/default.conf .

แก้ไข default.conf โดยแก้ไข document root ไปที่ /var/www/html และ uncomment ในส่วนของ php และแก้ค่าดังนี้

location / {
root /var/www/html;
index index.php index.html index.htm;
}
location ~ \.php$ {
root /var/www/html;
fastcgi_pass php:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}

ตรงนี้ระวังนะครับให้สังเกตตัวหน้าที่ผมทำไว้ใน config แก้ให้ตรงกับของเรา แก้ไขเสร็จแล้วก็ใส่กลับเข้าไปใน container

$ docker cp  default.conf nginx:/etc/nginx/conf.d/default.conf

ทดสอบ config

$ docker exec nginx nginx -t

reload nginx

$ docker exec nginx nginx -s reload

ลองเรียกหน้าเว็บดู

ตอนนี้เรียกหน้าเว็บไม่ได้ ลองสร้าง index.html

$ echo Hello  >web/index.html

แล้ว php ทำงานได้จริงไหม ? ลองสร้าง index.php

$ echo '<?php phpinfo();?>' >web/index.php

ลองเรียกหน้าเว็บดูครับ

ตอนนี้เรา connect nginx และ php-fpm ได้เรียบร้อยแล้วเหลือ MariaDB ลอง run mariadb container กันดูครับ

Run MariaDB container

$ docker run -d --name db --hostname db --net net01 -e MYSQL_ROOT_PASSWORD=password mariadb

ถ้าต้องการเก็บ /var/lib/mysql ไว้ด้วยแนะนำให้ mount ด้วย -v นะครับแต่ในที่นี้ผมไม่ได้ซีเรียสเรื่องข้อมูลก็ run เท่านี้ อ้อ ถ้าจะตั้งรหัสผ่านของ root ก็ให้ตั้งค่า env โดยใช้ -e MYSQL_ROOT_PASSWORD=xxx ได้ต่ามต้องการครับ

ปรับแต่ง php fpm container

php fpm ปกติจะไม่มี ตัว connect กับ mysql เราจำเป็นต้องติดตั้ง (ให้ทำ Dockerfile ในกรณี production หรือ dev จริงจัง) ตอนนี้เล่นๆ เราก็เข้าไปยัง php fpm กัน คำสั่ง docker-php-ext-install มีเฉพาะ image ของ php ที่เป็น official นะครับ เราจะติดตั้ง อะไรเพิ่มเข้าไปก็ใช้คำสั่งนี้ เพราะ image เริ่มต้นของ php จะไม่มีอะไรมาให้

$ docker  exec -it php bash --login

ติดตั้ง php mysqli plugin

root@php:/var/www/html# docker-php-ext-install mysqli

เมื่อติดตั้งเสร็จให้ทำการ restart container หนึ่งรอบ

$ docker restart php

ลองตรวจสอบว่า mysqli ทำงานหรือยัง

$ docker  exec  php php -m

เมื่อได้แล้วคราวนี้เราก็สามารถพัฒนาเว็บได้แล้ว ลองเขียนโค้ดสักหนึ่งกระบวนยุทธ ผม copy code มาจาก W3C

$ pico -w web/db.php

copy ข้างล่างใส่ใน db.php

<?php
$servername = "db";
$username = "root";
$password = "password";
// Create connection
$conn = new mysqli($servername, $username, $password);
// Check connection
if ($conn->connect_error) {
die("Connection failed: " . $conn->connect_error);
}
echo "Connected successfully";
?>

การกำหนดค่า mysql เมื่ออยู่ใน docker container และ เชื่อมต่อ network เดียวกันเราสามารถตั้งค่า servername เป็นชื่อ container ได้เลย ดังตัวอย่างผมก็ใส่ db ลงไป ส่วน port ถ้าไม่ใส่ก็จะเป็นค่า default 3306 สังเกตตอน run ผมไม่ได้ map port 3306 ออกมาเลย ซึ่งในวง network เดียวกันจะเชื่อมต่อและมองเห็น port กันโดยอัตโนมัตินะครับ

การทำงานของโค้ดนี้ถ้าทำงานถูกต้องจะขึ้นว่า Connected successfully ลองเรียกหน้าเว็บกันดู

จากตัวอย่าง พอจะมองภาพออกนะครับว่าเราจะเอาไปประยุกต์ใช้ต่อกันยังไง จบ 4 EP ผมว่าเราก็สามารถนำ docker มา dev ได้อย่างสบายๆ แล้วละ สำหรับ EP ต่อๆ ไปผมคงยก ตัวอย่างการใข้งานแบบต่างๆ ตามที่ผมทำได้และทำเป็นมาบันทึกไว้ให้เพื่อนๆ newbie ได้ศึกษากันมีข้อแนะนำ หรือ ข้อสงสัยก็ respone กลับมาได้นะครับยินดีรับฟังครับ

--

--