Category: Linux (OS, shell script, etc)

  • วิธีขยาย Disk ใน VM/Virtualbox แล้วให้ Ubuntu

    ในกรณีใช้ VMWare/VirtualBox  บางครั้งเราต้องการขยาย Disk ให้ Ubuntu มีพื้นที่มากขึ้น

    1. เดิมมี Disk 100 GB
    2. แก้ไขให้เป็น 300 GB
    3. Login เข้าไป ดูข้อมูล ด้วยคำสั่ง df -h จะเห็น 100 GB อยู่

      แล้ว sudo reboot
    4. ลอง Login ใหม่ แล้วใช้คำสั่ง
      sudo su
      fdisk -l

      ก็จะ ขนาดเพิ่มเป็น 300 GB
      จากนั้นใช้คำสั่ง

      growpart /dev/sda 1
      resize2fs /dev/sda1

      แล้วลอง

      df -h


      ก็จะพบว่า ได้ขนาดมาเป็น 300 GB แล้ว

  • Windows CRLF to Unix LF Issues in Cygwin Shell Script

    เมื่อเรารัน shell script ของโปรแกรม Cygwin for Windows ซึ่งมีการเขียนคำสั่งไปตัดเอาข้อความผ่านคำสั่ง (Command Line) ของ Windows มาใส่ในตัวแปรของ shell script

    เช่น ในตัวอย่างนี้คือคำสั่ง ipconfig เมื่อได้ข้อความที่ต้องการมาเราจะได้ \r แถมมาให้ด้วยต่อท้าย เพราะ Windows style line ending จะมี CRLF (\r\n)  ในขณะที่ Linux style line ending จะมี LF (\n) เท่านั้น

    น่าแปลกใจมากว่า เราเคยรัน shell script นี้ใน Windows 7 ใช้งานได้ แต่พอเป็น Windows 10 build 1709 มันรันไม่ได้

     

    ปัญหา

    เมื่อเปิด Cygwin Terminal ขึ้นมา จะได้เป็น bash shell

    ในไฟล์ test.sh ดังตัวอย่างข้างล่างนี้ เมื่อสั่งรัน จะพบว่าพบข้อผิดพลาด ตัวแปร ZONEX จะไม่มีค่า ซึ่งจริง ๆ จะต้องได้คำว่า zone1
    $ cat test.sh

    #!/bin/bash
    
    DHCPSERVER=$(ipconfig /all | grep -i "DHCP Server" | cut -d: -f2 | xargs)
    
    MAC=$(ipconfig /all | grep -A4 -i "^Ethernet Adapter Ethernet" | tail -1 | cut -d\: -f2 | tr - : | xargs)
    
    ZONEX=$(curl -s http://${DHCPSERVER}/dhcpd.txt | grep -i ${MAC} | awk '{print $2}' | cut -d'_' -f1)
    
    echo "DHCP SERVER is ${DHCPSERVER}"
    echo "MAC is ${MAC}"
    echo "Zone is ${ZONEX}"

    สั่งรันดูผลลัพธ์ด้วยคำสั่ง bash test.sh

    $ bash test.sh
    DHCP SERVER is 192.168.6.150
    MAC is 50:7B:9D:30:2E:4B
    Zone is

    ผมก็ตรวจสอบด้วยวิธีการ debug คือ เพิ่ม -x ดังตัวอย่างนี้

    $ bash -x test.sh
     ++ ipconfig /all
     ++ grep -i 'DHCP Server'
     ++ cut -d: -f2
     ++ xargs
     + DHCPSERVER=$'192.168.6.150\r'
     ++ ipconfig /all
     ++ grep -A4 -i '^Ethernet Adapter Ethernet'
     ++ tail -1
     ++ cut -d: -f2
     ++ tr - :
     ++ xargs
     + MAC=$'50:7B:9D:30:2E:4B\r'
     ++ curl -s $'http://192.168.6.150\r/dhcpd.txt'
     ++ grep -i $'50:7B:9D:30:2E:4B\r'
     ++ awk '{print $2}'
     ++ cut -d_ -f1
     + ZONEX=
     ' echo 'DHCP SERVER is 192.168.6.150
     DHCP SERVER is 192.168.6.150
     ' echo 'MAC is 50:7B:9D:30:2E:4B
     MAC is 50:7B:9D:30:2E:4B
     + echo 'Zone is '
     Zone is

    จึงพบว่า ตัวแปร DHCPSERVER และ ตัวแปร MAC จะมี “/r” แถมมาให้ด้วย ซึ่งเป็นส่วนเกินที่ทำให้คำสั่งถัดไปทำงานผิดพลาดทำให้ได้ค่า ZONEX เป็น ว่างเปล่า

     

    วิธีแก้ไข เราต้องใส่ option ” -o igncr ” หลังคำสั่ง bash เพื่อให้ตัด “/r” ออกไป

    สั่งรันดูผลลัพธ์ด้วยคำสั่ง bash -o igncr test.sh

    ผลลัพธ์คราวนี้ถูกต้องแล้ว

    $ bash -o igncr test.sh
    DHCP SERVER is 192.168.6.150
    MAC is 50:7B:9D:30:2E:4B
    Zone is zone1

     

    วิธีแก้อีกวิธีคือ หากไม่ใส่ option ที่ว่านี้ เราก็ต้องไปแก้ไขบรรทัดคำสั่ง เพื่อเติม sed ‘s/\r$//’ ต่อท้าย เป็นการตัด /r ออกไปก่อนนำค่าที่ได้ไปใส่ในตัวแปร DHCPSERVER
    เช่น

    DHCPSERVER=$(ipconfig /all | grep -i "DHCP Server" | cut -d: -f2 | xargs | sed 's/\r$//')

    ซึ่งก็ทำได้เช่นกัน แต่ต้องแก้ไขไฟล์ shell script ซึ่งก็แล้วแต่ชอบวิธีไหน

     

    Reference
    https://stackoverflow.com/users/1010997/user1010997
    https://stackoverflow.com/questions/11616835/r-command-not-found-bashrc-bash-profile
    https://stackoverflow.com/questions/18608380/r-command-not-found

  • วิธี upgrade Node.js ใน Bash ของ Windows 10 ให้เป็นรุ่นปัจจุบัน

    ปัญหาคือ บน Windows 10 เราสามารถใช้ Windows Subsystem for Linux (WSL) หรือ Bash Shell ได้ ซึ่งจริงๆมันก็คือ Ubuntu 16.04.3

    แต่ว่า เวลาจะใช้งาน Node.js ติดตั้งพวก Firebase, Angular อะไรพวกนี้ จะทำไม่ได้ เพราะรุ่นที่ให้มามันเก่ามาก

    วิธีการคือ (Reference: https://nodejs.org/en/download/package-manager/#debian-and-ubuntu-based-linux-distributions)

    ใช้คำสั่งต่อไปนี้

    curl -sL https://deb.nodesource.com/setup_8.x | sudo -E bash -
    apt-get install -y nodejs

    ก็เรียบร้อย

  • วิธีติดตั้งระบบ Cyrus IMAP Cluster (Cyrus Murder)

    ต่อจาก
    Mail Clustering with Cyrus Murder และ How Cyrus Murder (Mail Clustering) work?

    คราวนี้ มาลง รายละเอียดทีละขั้นตอน

    ระบบ Cyrus IMAP Cluster หรือ Cyrus Murder นี้ ประกอบด้วยเครื่องคอมพิวเตอร์ ขั้นต่ำ 3 เครื่อง คือ frontend, backend, mupdate ต่อไปนี้ จะเป็นวิธีการทำ แต่ละเครื่อง

     

    Prerequisite

    ทั้งหมดเป็น Ubuntu 16.04 Server, ทำการ update และ upgrade แล้ว และ เข้า SSH ด้วย user ที่สามารถ sudo ได้ และรุ่นของ cyrus-imapd, cyrus-murder ที่ใช้เป็น 2.4.18
    ทุกเครื่อง มี user ชื่อ ‘cyrus’ และ ทำการตั้งรหัสผ่านไว้เรียบร้อย
    เฉพาะเครื่องที่เป็น Backend จะต้องมี uesr ชื่อ ‘mailproxy’ และทำการตั้งรหัสผ่านไว้เรียบร้อย ด้วยอีก 1 คน
    ในที่นี้ จะใช้ pam-ldap ติดตั้งใน Backend ทุกเครื่อง

    MUPDATE ( mupdate1.example.com )

    1. ติดตั้ง cyrus-murder ด้วยคำสั่ง
      sudo apt install cyrus-murder cyrus-common sasl2-bin

      ระบบจะติดตั้งตั้งโปรแกรมที่เกี่ยวข้อง รวมถึง postfix ด้วย ให้เลือกเป็น No configuration ไป

    2. แก้ไขไฟล์ /etc/cyrus.conf ใน Section “SERVICES” ประมาณบรรทัดที่ 62 ให้ uncomment เพื่อได้บรรทัดนี้
      mupdate       cmd="mupdate -m" listen=3905 prefork=1

      จุดสำคัญคือ mupdate -m คือ ตัวที่จะบอกว่า ทำหน้าที่เป็น MUPDATE Master

    3. แก้ไขไฟล์ /etc/imapd.conf เพื่อกำหนด admins ในที่นี้ให้ใช้ชื่อ cyrus โดยการ uncomment ประมาณบรรทัดที่ 55
      และแก้ sasl_pwcheck_method เป็น saslauthd

      sasl_pwcheck_method: saslauthd
      sasl_mech_list: PLAIN
      admins: cyrus
    4. จากนั้น start ระบบขึ้นมา จะพบว่ามีการเปิด port 3905 รออยู่
      sudo /etc/init.d/cyrus-imapd start
      netstat -nl | grep 3905
    5. แก้ไขไฟล์ /etc/default/saslauthd บรรทัดที่ 7
      START=yes

      แล้ว start saslauthd

      sudo /etc/init.d/saslauthd start

    BACKEND ( backend01.example.com)

    1. ติดตั้ง
      sudo apt install cyrus-imapd cyrus-common cyrus-clients sasl2-bin
    2. แก้ไขไฟล์ /etc/imapd.conf โดยเพิ่มบรรทัดต่อไปนี้ไว้ท้ายไฟล์
      #SASL
      sasl_pwcheck_method: saslauthd
      sasl_mech_list: PLAIN
      
      # MUPDATE
      servername: backend01.example.com
      admins: cyrus   
      proxyservers:   mailproxy
      lmtp_admins: mailproxy
      mupdate_server: mupdate.example.com
      mupdate_port: 3905
      mupdate_username: cyrus
      mupdate_authname: cyrus
      mupdate_password: <secret>
      
    3. แก้ไข /etc/cyrus.conf
      ใน START section ให้ uncomment

      mupdatepush cmd="/usr/sbin/cyrus ctl_mboxlist -m"
    4. เพิ่มส่วนนี้ ท้ายไฟล์ /etc/services ด้วย
      #MUPDATE
      mupdate 3905/tcp # MUPDATE
      mupdate 3905/udp # MUPDATE
    5. *** ติดตั้ง PAM LDAP
      sudo apt-get install ldap-auth-client nscd

      ตั้งค่าต่อไปนี้

      LDAP server Uniform Resource Identifier: ldap://ldap.your.domain/
      Distinguished name of the search base: dc=example,dc=com
      LDAP version to use: 3
      Make local root Database admin: No
      Does the LDAP database require login? No

      ต่อไป สั่งให้ระบบแก้ไขเงื่อนไขการ authen เป็น LDAP

      sudo auth-client-config -t nss -p lac_ldap

      จากนั้นใช้คำสั่งต่อไปนี้ เพื่อเริ่มใช้งาน PAM LDAP

      sudo pam-auth-update

      จะมีคำถามว่า
      PAM profiles to enable:
      ให้เลือกทั้ง
      Unix authentication และ
      LDAP Authentication

      สุดท้าย

      sudo /etc/init.d/nscd restart
    6. แก้ไขไฟล์ /etc/default/saslauthd บรรทัดที่ 7
      START=yes

      แล้ว start saslauthd

      sudo /etc/init.d/saslauthd start

    FRONTEND ( frontend01.example.com )

    1. ติดตั้ง
      sudo apt install cyrus-imapd cyrus-common cyrus-clients sasl2-bin
    2. แก้ไขไฟล์ /etc/imapd.conf โดยเพิ่มบรรทัดต่อไปนี้ไว้ท้ายไฟล์
      #SASL
      sasl_pwcheck_method: saslauthd
      sasl_mech_list: PLAIN
      
      # MUPDATE
      mupdate_server: mupdate.example.com
      mupdate_port: 3905
      mupdate_username: cyrus
      mupdate_authname: cyrus
      mupdate_password: <secret>
      
      #PROXY
      serverlist: backend01.example.com
      backend01_password: mailproxy
      proxy_authname: mailproxy
      
    3. แก้ไข /etc/cyrus.conf
      ใน SERVICE section ให้ uncomment

      mupdate cmd="mupdate" listen=3905 prefork=1
    4. เพิ่มส่วนนี้ ท้ายไฟล์ /etc/services ด้วย
      #MUPDATE
      mupdate 3905/tcp # MUPDATE
      mupdate 3905/udp # MUPDATE
    5. แก้ไขไฟล์ /etc/default/saslauthd บรรทัดที่ 7
      START=yes

      แล้ว start saslauthd

      sudo /etc/init.d/saslauthd start

    และ เมื่อทุกอย่างพร้อม ทุกเครื่องก็

    sudo /etc/init.d/cyrus-imapd restart

    เมื่อจะเพิ่มเครื่อง Backend ก็ทำตามขั้นตอน แล้ว เพิ่มใน /etc/imapd.conf ของเครื่อง Frontend ในส่วนของ serverlist และ password เช่น
    จะเพิ่มเครื่อง backend02.example.com ก็ต้องเพิ่มดังนี้

    #PROXY
    serverlist: backend01.example.com backend02.example.com
    backend01_password: <secret>
    backend02_password: <secret>
    proxy_authname: mailproxy

    เมื่อต้องการเพิ่ม Frontend ก็ให้ Sync ตัวไฟล์ /etc/imapd.conf ไปให้เหมือนกันทุกเครื่อง

    หวังว่าจะเป็นประโยชน์

  • GCP #01 วิธีการสร้าง Virtual Machine บน Google Cloud Platform

    ขั้นตอน

    1. มี Google Account
    2. ไปที่ https://console.cloud.google.com/start
    3. สำหรับคนที่ใช้ครั้งแรก ควรจะใช้สิทธิ์ Free Trial 300 USD / 12 Month

    4. ในการใช้งาน จะต้องมี Billing Account โดยต้องกรอกข้อมูล บัตร Credit/Debit ซึ่งต้องเป็น VISA/MasterCard เท่านั้น และต้องไม่ใช่ Prepaid ด้วย
      https://cloud.google.com/billing/docs/how-to/payment-methods#add_a_payment_method
    5. เมื่อเสร็จแล้วจะได้ Credit อย่างนี้
    6. ต่อไป สร้าง Virtual Machine กัน
      ไปที่ เมนู > Cloud Launcher

      จะเห็นได้ว่า ตอนนี้ระบบจะสร้าง “My First Project” ไว้ให้ ซึ่งเราสามารถ สร้าง Project ใหม่ก็ได้ แต่ตอนนี้ใช้อย่างนี้ไปก่อน
    7. ต่อไป จะลองสร้าง Ubuntu Server ขึ้นมาใช้งาน ในที่นี้จะสร้าง Ubuntu 14.04
      พิมพ์ Ubuntu ในช่องค้นหา แล้ว เลือก Ubuntu 14.04
    8. จากนั้น คลิก Launch on Compute Engine
    9. ตั้งชื่อตามต้องการ (ถ้าต้องการ)
    10. สามารถเลือก Zone และ Machine Type ได้ตามความเหมาะสม ซึ่งจะมีราคาแตกต่างกัน
    11. ค่าเริ่มต้น Machine Type: n1-standard-1 จะให้ 1 vCPU, 3.75 GB RAM และ 10 GB standard persistent disk หากต้องการ Disk เพิ่ม สามารถคลิก Change เพื่อเพิ่มได้​ (standard persistent disk จะราคาถูกกว่า ssd มาก)
    12. ต่อไป กำหนดเรื่องเของ Firewall ถ้าให้บริการ HTTP/HTTPS ก็คลิกเลือกได้เลย
      ในกรณีที่ต้องการกำหนดค่าอื่นๆ เช่น Disk, Network, SSH Key ให้คลิก “Management, disks, networking, SSH keys”
      เสร็จแล้วกดปุ่ม Create
    13. รอสักครู่ ก็จะได้ VM มาใช้งานแล้ว
    14. ในที่นี้ จะได้ External IP ซึ่งใช้ในการติดต่อจาก Internet มา แต่หากมีการ Restart/Stop IP address นี้ก็จะเปลี่ยนไป (การ Fix มีค่าใช้จ่ายนิดหน่อย) และ การติดต่อไปยัง VM ก็สามารถทำได้ โดยการคลิก SSH ซึ่งสามารถเข้าถึงได้จาก Console นี้ หากต้องการใช้งานจาก Client อื่นก็ทำได้ แต่ต้องกำหนด SSH Key กันนิดหน่อย ซึ่งจะกล่าวในภายหลัง
    15. เพิ่มเติม ในกรณีต้องการเปิด Port เพิ่มที่ไม่ใช่ HTTP/HTTPS ให้คลิกที่ Menu > Network Services > Firewall Rules

      แล้วกำหนดค่าตามต้องการ โดยการ Create Firewall Rule

    หวังว่าจะเป็นประโยชน์ครับ

  • วิธีทำ Password-less SSH บน Ubuntu

    ในการทำงานกับ Server Cluster ขนาดใหญ่ ซึ่งประกอบด้วย Ubuntu Server จำนวนมาก หากต้องแก้ไขระบบทั้งหมด โดยการ Secure Shell หรือ SSH เข้าไปทีละเครื่อง “โดยต้องเป็น root ด้วย” จะเป็นงานที่ใช้เวลาอย่างมาก เค้าจึงมีระบบที่เรียกว่า Password-less SSH โดยการแลกเปลี่ยน Public Key แทนที่จะต้อง Login ด้วย Username/Password

    และเนื่องจาก Ubuntu โดย Default ไม่มีการสร้าง root password (มี root แต่ไม่มี password –> ก็เลย Login ไม่ได้ด้วย Password) ซึ่งก็ดีในเรื่องของ Security แต่ทำให้การทำงานยุ่งยากนิดหน่อย

    บทความนี้จะกล่าวถึงวิธีการทำ Password-less SSH รวมไปถึง การที่ไม่ต้องถาม Known Host ในครั้งแรกที่เข้าใช้งานด้วย โดยระบบจะประกอบด้วย server01 เป็นเครื่องที่จะสั่งการเครื่อง server02 … serverNN ในสิทธิ์ root และในระบบนี้ ทุกเครื่องมี user ชื่อ mama ซึ่งมีสิทธิ์ sudo

    ที่เครื่อง server01

    1. ใช้คำสั่งต่อไปนี้ เพื่อสร้าง Public/Private rsa key pair
      ssh-keygen

      จะได้ผลดังนี้

      ซึ่งจะได้ไฟล์มา 2 file อยู่ใน directory: ~/.ssh
      – id_rsa
      – id_rsa.pub

    2. เพื่อไม่ให้การ SSH ไปยังเครื่องใหม่ๆ มีการถาม Known Host แบบนี้ แล้วก็ต้องคอยตอบ yes ทุกเครื่องไป

      ก็ให้สร้างไฟล์ .ssh/config ว่า (วิธีนี้จะมีผลเฉพาะ mama เท่านั้น) หรือสร้างใน /etc/ssh/ssh_config เพื่อให้มีผลทั้งระบบ

      Host *
       StrictHostKeyChecking no
       UserKnownHostsFile=/dev/null
    3. จากนั้น ให้เอาไฟล์ Public Key คือ  .ssh/id_rsa.pub  ไปยังเครื่องปลายทาง ในที่นี้คือ server02 (ใช้วิธี scp ไปยัง mama@server02)
      scp .ssh/id_rsa.pub mama@server02:~

      ในครั้งแรกนี้ ยังต้องใส่ Password ของ mama บนเครื่อง server02 อยู่
      จากนั้น ไปดำเนินการต่อใน server02

    ที่เครื่อง server02

    1. ใน home directory ของ mama บน server02 จะมีไฟล์ id_rsa.pub อยู่ ลองตรวจสอบโดยใช้คำสั่ง
      ls -l /home/mama/id_rsa.pub
    2. เปลี่ยนเป็น root ด้วยคำสั่ง
      sudo su

      แล้ว เข้าไปใน root home directory ด้วยคำสั่ง

      cd
    3. สร้าง directory .ssh และ สร้างไฟล์ .ssh/authorized_keys โดยนำข้อมูลในไฟล์ /home/mama/id_rsa.pub มาต่อท้าย
      mkdir .ssh
      cat /home/mama/id_rsa.pub >> .ssh/authorized_keys
    4. เพื่อความปลอดภัย ตั้งค่า Permission ให้ถูกต้อง
      chmod 700 .ssh
      chmod 600 .ssh/authorized_keys

     

    จากนั้น ลองทดสอบ ssh จาก mama บน server01 ไปยัง root บน server02

    ssh root@server02

    ก็จะไม่มีการถาม Password และ ไม่ถาม Known Host อีก

    หลังจากนี้ สามารถ clone เครื่อง server02 ไปเป็นเครื่องต่างๆได้เลย

  • เตาะแตะไปกับ Docker ตอนที่ 12 Clone Docker Files From GitHub

    จากบล็อกเรื่อง “เตาะแตะไปกับ Docker” ในตอนที่แล้ว เราได้เรียนรู้ขั้นตอนในการสร้างและรัน LDAP services อย่างละเอียด ก่อนที่ผมจะเขียนบทความในตอนนี้ผมได้นำไฟล์ทุกไฟล์นั้นขึ้นไปไว้บน GitHub เพื่อให้พวกเราไม่ต้องสร้างไฟล์เหล่านั้นเอง แต่จะทำด้วยคำสั่ง git clone ครับ

    เรายังคงทดสอบด้วย VM โดยตั้งค่า network เป็น NAT network เพราะว่า เราใช้ domain สมมติ คือ ldap.example.com และทดสอบในสภาพแวดล้อมที่เป็นเครือข่ายภายใน

    ขั้นตอนดังนี้

    1. ติดตั้ง Ubuntu 16.04 64 bit แล้วติดตั้ง docker 17.06.2-ce แล้วต้องเปลี่ยนชื่อ hostname เป็น ldap.example.com จากนั้นรีบูตเครื่อง

    2. ติดตั้ง docker-compose 1.8.0-2 (ถ้ายังไม่ได้ทำ) ด้วยคำสั่งดังนี้

    sudo apt install docker-compose

    3. ทำการ Clone project จาก github ด้วยคำสั่ง

    git clone https://github.com/woonpsu/ex1-openldap.git

    4. ทำคำสั่งตามนี้

    cd ex1-openldap
    docker-compose up -d

    หมายเหตุ
    หากยังไม่มี image ชื่อ ubuntu:16.04 ก็จะใช้เวลานานสักหน่อยเมื่อรันคำสั่ง docker-compose เพราะว่าจะมีการสร้าง image ubuntu:16.04 ให้ใหม่

    5. ใช้คำสั่งเหล่านี้เพื่อตรวจสอบ

    docker images
    docker ps
    docker volume ls

    6. เพิ่ม users ตัวอย่าง

    sudo apt install ldap-utils
    ldapadd -H ldap://ldap.example.com -f ./openldap/src/create-users.ldif -x -D "cn=admin,dc=example,dc=com" -w 123456

    7. ทดสอบเข้าใช้งานเว็บจากเครื่องใน NAT network เดียวกัน หรือที่เครื่อง VM server ที่ผมได้ติดตั้ง Desktop Environment ไว้แล้ว ก็ต้องเปลี่ยนจาก text เป็น graphic ด้วยคำสั่ง

    $ startx

    เข้า browser ไปที่

    http://ldap.example.com:8080/phpldapadmin/

     

    สำหรับวิธีการทำ GitHub Repository ชื่อ ex1-openldap ของผมอย่างคร่าว ๆ คือ
    1. เข้า browser ไป sign up แบบ free ที่ github.com ด้วย username ชือ woonpsu

    2. สร้าง Repository ชื่อ ex1-openldap

    3. ไปที่เครื่อง server ใช้คำสั่ง

    git clone https://github.com/woonpsu/ex1-openldap.git

    4. เตรียมไฟล์

    cd ex1-openldap
    git init

    5. สร้างไฟล์ docker-compose.yml และไดเรกทอรี openldap กับ phpldapadmin ให้เสร็จ

    6. ทำการส่งขึ้นไปไว้บน github

    git add .
    git commit -m “This is a first commit”
    git push -u origin master

    ใส่ username และ password ของเราที่ sign up กับ github

     

    หมายเหตุ

    • หากต้องการใช้ VM ที่ผมเตรียมไว้ จะไม่ต้องติดตั้ง Ubuntu server ก็ download docker-vm file size 1.2G แล้ว import เข้า Oracle VM Virtualbox ทดสอบดูได้ (เข้าด้วย mama/123456)

     

  • เตาะแตะไปกับ Docker ตอนที่ 11 Docker Compose (LDAP services)

    เราจะมาเรียนรู้ การใช้ docker compose รัน service 2 services คือ OpenLDAP และ phpLDAPadmin ซึ่ง docker จะมองว่าการใช้ docker compose คือ เรากำลังรัน project ที่ประกอบด้วย service หลาย ๆ service

    ให้แน่ใจว่าอยู่ที่ home directory ให้ใช้คำสั่งนี้

    $ cd

    สร้างไดเรกทอรีของ project สมมติตั้งชื่อว่า ex1

    $ mkdir ex1
    $ cd ex1

    สร้างไดเรกทอรี openldap ภายในมี dockerfile และไดเรกทอรีที่เกี่ยวข้อง ทำตามบล็อกเรื่อง “เตาะแตะไปกับ Docker ตอนที่ 9 Dockerfile (OpenLDAP)

    สร้างไดเรกทอรี phpldapadmin ภายในมี dockerfile และไดเรกทอรีที่เกี่ยวข้อง ทำตามบล็อกเรื่อง “เตาะแตะไปกับ Docker ตอนที่ 10 Dockerfile (phpLDAPadmin)

    สร้างไฟล์ docker-compose.yml ด้วยเอดิเตอร์ที่ถนัด เช่น vi หรือ nano ก็ได้

    $ vi docker-compose.yml
    
    version: '2'
    services:
     openldap:
      build: ./openldap
      container_name: openldap
      volumes:
       - ldapdatavol:/var/lib/ldap
       - ldapconfigvol:/etc/ldap/slapd.d
      ports:
       - "389:389"
       - "636:636"
      restart: always
    
     phpldapadmin:
      build: ./phpldapadmin
      container_name: phpldapadmin
      environment:
       HNAME: "openldap"
      ports:
       - "8080:80"
      depends_on:
       - openldap
      restart: always
    
    volumes:
     ldapdatavol:
      external: false
     ldapconfigvol:
      external: false

    อธิบายได้ดังนี้
    ไฟล์ docker-compose.yml นี้ จะมี service แรกคือ openldap จะ build image จากไดเรกทอรี ./openldap เมื่อรันเป็น container จะตั้งชื่อว่า openldap โดยมีที่เก็บข้อมูลถาวรคือ ldapdatavol จะ mapped ไปยัง /var/lib/ldap ใน container และที่เก็บคอนฟิก ldapconfigvol จะ mapped ไปยัง /etc/ldap/slapd.d ใน container เช่นเดียวกัน
    โดย Host และ container เปิด port ตรงกัน คือ เปิด port TCP 636(LDAPS) และ 389(LDAP) และ container นี้จะทำงานทุกครั้งเมื่อเปิดเครื่อง

    ต่อมา service ที่สองคือ phpldapadmin จะ build image จากไดเรกทอรี ./phpldapadmin เมื่อรันเป็น container จะตั้งชื่อว่า phpldapadmin มีการตั้งค่าตัวแปร HNAME เป็นชื่อ container อันแรก คือ openldap โดยที่ Host จะเปิด port TCP 8080 ไปยัง port TCP 80 ของ container นี้ ถัดมาคือ depends_on คือ จะรัน container นี้ได้ก็ต่อเมื่อมี container ชื่อ openldap และ container นี้จะทำงานทุกครั้งเมื่อเปิดเครื่อง

    ท่อนล่างสุด คือ การกำหนดว่า จะมีการใช้ named volume ชื่อ ldapdatavol และ ldapconfigvol ทั้งสอง volume นี้ จะถูกสร้างโดยคำสั่ง docker-compose ไม่ได้ไปใช้ volume จากที่ได้สร้างไว้ก่อนแล้ว (external: false) หากจะย้อนกลับไปอ่านเรื่อง “เตาะแตะไปกับ Docker ตอนที่ 7 Manage data” จะเข้าใจเรื่อง named volume ครับ

    ผลลัพธ์หลังจากเตรียมครบ ภายในไดเรกทอรี ex1 จะมี 1 ไฟล์ และ 2 ไดเรกทอรี ดังนี้

    $ ls 
    docker-compose.yml openldap phpldapadmin

    ตอนนี้เราก็เตรียมการต่าง ๆ เสร็จแล้ว

    ต่อไปก็ใช้คำสั่ง docker-compose เพื่อสร้าง service คือ openldap และ phpldapadmin ดังนี้

    $ docker-compose up -d

    ตรวจสอบรายการ image

    $ docker images
    REPOSITORY TAG IMAGE ID CREATED SIZE
    phpldapadmin latest d314c021fd1a 6 hours ago 282MB
    ex1_phpldapadmin latest f2feaa90c59b 9 days ago 282MB
    ex1_openldap latest e98f6bad71a7 9 days ago 259MB
    openldap latest cb8b1c0057cc 11 days ago 259MB
    ubuntu 16.04 ccc7a11d65b1 5 weeks ago 120MB

    จะพบว่ามี image ของ project ex1 คือ ex1_openldap และ ex1_phpldapadmin ส่วน image ชื่อ openldap และ phpldapadmin สองอันนั้นที่เห็นเป็น image ที่สร้างด้วยคำสั่ง docker build ตอนที่เราเรียนรู้เรื่อง “เตาะแตะไปกับ Docker ตอนที่ 9 Dockerfile (OpenLDAP)” และ “เตาะแตะไปกับ Docker ตอนที่ 10 Dockerfile (phpLDAPadmin)” ครับ

    ตรวจสอบรายการ container ที่รันอยู่

    $ docker ps
    CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
    b61e8f24802c ex1_phpldapadmin "/bin/bash /run.sh..." 3 minutes ago Up 3 minutes 0.0.0.0:8080->80/tcp phpldapadmin
    489bb2db70d3 ex1_openldap "/bin/sh -c '/usr/..." 3 minutes ago Up 3 minutes 0.0.0.0:389->389/tcp, 0.0.0.0:636->636/tcp openldap

    จะพบว่ามี container ชื่อว่า openldap และ phpldapadmin เกิดขึ้นหลังคำสั่ง docker-compose up -d

    ทดสอบการเข้าใช้งานทาง web ไปที่ http://ldap.example.com:8080/phpldapadmin/ (เนื่องจาก VM ที่ใช้ทดสอบ คือ ubuntu ที่ได้ติดตั้ง XFCE desktop environment ไว้ด้วยทำให้สามารถใช้งาน web browser ได้ด้วย)

    หลังจาก login แล้วจะเห็นข้อมูล LDAP และจัดการ LDAP database ได้

    จากความรู้ที่ได้เรียนมาหลาย ๆ ตอนจนถึงตอนนี้ เราก็น่าจะได้แนวทางในการสร้าง service ความเข้าใจอย่างง่าย ๆ คือ หากเป็น image ที่เราจะทำขึ้นเอง ไม่ได้ไป pull จาก docker hub เราก็ทำด้วย dockerfile และหากมี service ที่ใช้ร่วมกันระหว่าง service ก็เปลี่ยนไปทำต่อด้วย docker-compose จะสะดวกกว่า

    อนึ่งหาก pull หรือมี image อยู่แล้ว ก็เปลี่ยนจาก build: ./openldap เป็น image: openldap และปรับแก้ไขนิดหน่อยตามที่ผู้พัฒนา image นั้นได้แจ้งวิธีการไว้ครับ

    จากที่ได้เขียนบล็อกในชุด “เตาะแตะไปกับ Docker” ตั้งแต่ ตอนที่ 1 ถึง ตอนที่ 11 นี้ ผมคิดว่าก็น่าจะเพียงพอให้เข้าใจว่า docker ใช้งานอย่างไร หวังเป็นอย่างยิ่งว่าผู้อ่านคงได้รับความรู้กันครับ และสามารถลองทำตามได้โดยไม่ติดขัดอะไร

     

  • เตาะแตะไปกับ Docker ตอนที่ 10 Dockerfile (phpLDAPadmin)

    ในตอนที่แล้วเราใช้งาน openldap ด้วยคำสั่ง เช่น ldapsearch หรือ ldapadd ได้แล้ว วันนี้เราจะเรียนรู้การใช้ dockerfile สร้าง image ชื่อ phpldapadmin เพื่อใช้เป็น web interface ในการเข้าไปจัดการ LDAP database ของ container ชื่อ openldap โดยที่ phpLDAPadmin นี้คือการรัน php บน apache2 แล้วเราจะติดต่อระหว่าง container กันได้อย่างไร มาดูกันครับ

    เช่นเดียวกับครั้งที่แล้ว ผมจะแยกเป็น 3 ขั้นตอน คือ 1.ขั้นตอนเตรียมไฟล์ที่เกี่ยวข้อง 2.ขั้นตอนสร้างไฟล์ dockerfile และ 3.ขั้นตอนการรัน container

     

    1.ขั้นตอนเตรียมไฟล์ที่เกี่ยวข้อง

    ให้แน่ใจว่าอยู่ที่ home directory ให้ใช้คำสั่งนี้

    $ cd

    สร้างไดเรกทอรีของ image ที่เราจะสร้าง

    $ mkdir phpldapadmin
    $ cd phpldapadmin
    $ mkdir src

    เราจะเตรียมไฟล์ชื่อ apache2-foreground ให้เปิดไฟล์จากที่นี่ https://github.com/docker-library/php/blob/master/5.6/jessie/apache/apache2-foreground แล้วคัดลอกทุกบรรทัด นำมาสร้างไฟล์ ด้วยเอติเตอร์ที่ถนัด เช่น vi หรือ nano ก็ได้

    $ vi ./src/apache2-foreground

     

    2.ขั้นตอนสร้างไฟล์ dockerfile

    ตอนนี้ก็มาถึงขั้นตอนการเขียน dockerfile ด้วยเอดิเตอร์ที่ถนัดเช่น vi หรือ nano ก็ได้

    $ vi dockerfile
    
    # Composer: Wiboon Warasittichai
    
    FROM ubuntu:16.04
    
    # Change apt source
    RUN sed -i 's/\/us.archive/\/th.archive/g' /etc/apt/sources.list && \
     sed -i 's/\/archive/\/th.archive/g' /etc/apt/sources.list
    
    # Update ubuntu, then install packages
    RUN apt-get update && \
    DEBIAN_FRONTEND=noninteractive apt install -y php-ldap phpldapadmin ldap-utils
    
    # Timezone Asia/Bangkok
    RUN apt-get install -y tzdata && \
     ln -sf /usr/share/zoneinfo/Asia/Bangkok /etc/localtime && \
     dpkg-reconfigure -f noninteractive tzdata
    
    # Cleaning
    RUN apt-get autoremove -y && apt-get clean -y
    
    EXPOSE 80
    
    CMD RUN ulimit -n 1024
    
    ENV HNAME ${HNAME}
    ADD ./src/startup.sh /startup.sh
    
    COPY ./src/apache2-foreground /usr/local/bin/
    RUN chmod +x /usr/local/bin/apache2-foreground
    
    ENTRYPOINT ["/bin/bash","/startup.sh"]

     

    ภายในไฟล์ dockerfile เราได้อ้างถึงการนำไฟล์ชื่อ startup.sh ก็ให้สร้างไฟล์นี้ด้วย

    $ vi ./src/startup.sh 
    
    #!/bin/bash
    
    sed -i "s/127.0.0.1/$HNAME/g" /etc/phpldapadmin/config.php
    /usr/local/bin/apache2-foreground

    จุดน่าสนใจในไฟล์ dockerfile ในตัวอย่างนี้ คือ เราจะเขียนอย่างไรเพื่อให้เราเปลี่ยนค่า 127.0.0.1 ในไฟล์ /etc/phpldapadmin/config.php ใน container ที่รันขึ้นมาได้อัตโนมัติ เราจึงต้องใช้ ENV ในการระบุว่า container openldap ที่รันอยู่นั้นใช้ IP อะไร แล้วเราก็นำ IP ใส่ลงไปในตัวแปร HNAME เพื่อจะติดต่อไปยัง container openldap ได้ถูกต้อง ผมจึงเพิ่มบรรทัดนี้

    ENV HNAME ${HNAME}

     

    3.ขั้นตอนการรัน container

    สร้าง image ด้วยคำสั่งนี้

    $ docker build -t phpldapadmin .

    ก่อนจะรัน container phpldapadmin ต้องไม่ลืมว่า เราจะต้องรัน container openldap ด้วยคำสั่งนี้แล้ว

    $ docker run -d -p 636:636 -p 389:389 --name openldap --volume oldata:/var/lib/ldap --volume olconfig:/etc/ldap/slapd.d openldap

    รัน container และ ตรวจสอบ ด้วยคำสั่งนี้

    $ LDAPSERVER=$(docker exec -it openldap cat /etc/hosts | tail -1 | cut -f1) && docker run -d -p 8080:80 --env HNAME=${LDAPSERVER} --name phpldapadmin phpldapadmin
    
    $ docker ps

    อธิบายได้ดังนี้ container จะรันแบบ detach (-d) เปิด port 8080 ที่ Host เข้าไปยัง port 80 ที่ container ตั้งชื่อ(–name) ว่า phpldapadmin โดยกำหนดค่า ENV สำหรับตัวแปรที่ชื่อ HNAME ให้ใช้ IP จากไฟล์ /etc/hosts ใน container openldap และรันจาก image ชื่อ phpldapadmin

    ทดสอบการเข้าใช้งานทาง web ไปที่ http://ldap.example.com:8080/phpldapadmin/ (เนื่องจาก VM ที่ใช้ทดสอบ คือ ubuntu ที่ได้ติดตั้ง XFCE desktop environment ไว้ด้วยทำให้สามารถใช้งาน web browser ได้ด้วย)

    หลังจาก login แล้วจะเห็นข้อมูล LDAP และจัดการ LDAP database ได้

    โปรดสังเกตว่าคำสั่ง docker run นั้น หากต้องการให้รันทำงานทุกครั้งที่เปิดเครื่อง เราจะสามารถใส่ option นี้เข้าไปได้ด้วย คือ –restart always ใส่หลังจากคำว่า docker run ก็ได้ครับ (ในตัวอย่างข้างต้น ผมไม่ได้ใส่ไว้ เพราะกำลังทดสอบ) หากเรา reboot เครื่อง container ทั้ง 2 ก็หายไปครับ

    แต่เราก็สามารถลบ container ได้ทันที ดังนี้

    $ docker stop phpldapadmin
    $ docker rm phpldapadmin
    $ docker stop openldap
    $ docker rm openldap

    สรุปว่า ในตอนนี้ เรารู้วิธีการใช้ dockerfile สร้าง container 2 อัน อันแรกคือ LDAP database และอีกอันคือ php web program ที่จะติดต่อกับ LDAP database ด้วยการใช้ตัวแปร ENV ร่วมด้วย

    ในตอนต่อไป เราจะมาเรียนรู้ การใช้ docker compose รันทั้ง 2 services นี้แทนการแยกสร้าง dockerfile และ run แยกกัน