Category: Virtual Machine

  • เตาะแตะไปกับ Docker ตอนที่ 3 Swarms

    ในตอนที่แล้ว เราทำ app ขึ้นมา และกำหนดค่าว่าจะรันเป็น service และเพิ่มจำนวน replicas เป็น 5x เพื่อให้บริการแบบ load-balancing แต่ทำบนเครื่อง host เครื่องเดียว
    เรียกได้อีกอย่างว่าเป็นการใช้ Docker แบบ a single-host mode แต่ในบทความนี้ เราจะเปลี่ยนให้ Docker ไปทำงานแบบ swarm mode โดยที่เมื่อเราใช้คำสั่ง docker deploy จะเป็นการ deploy app ของเราไปรันบน cluster ของเครื่องจำนวนหลาย ๆ เครื่อง

    ทำความเข้าใจกันสักเล็กน้อยเกี่ยวกับ Swarm Cluster
    swarm คือ เครื่องจำนวนหนึ่งที่รัน docker และได้ join เข้ามายัง cluster หลังจากนี้ในการรันคำสั่งใด ๆ ของ docker จะเรียกว่าเป็นการรันโดย swarm manager และเครื่องเหล่านี้ซึ่งอาจเป็น physical หรือ virtual machine ก็ได้ จะถูกเรียกว่า nodes

    swarm manager คือ เครื่องที่สามารถสั่งหรืออนุญาตให้เครื่องอื่น join เข้ามา และเครื่องนั้นจะถูกเรียกว่า workers เราจะเพิ่มเครื่อง workers เพื่อเป็นการนำมาช่วยในเรื่องของเพิ่มจำนวนหน่วยทำงานเท่านั้น และการสั่งคำสั่งเพื่อสร้าง app ยังคงต้องทำที่เครื่อง manager เหมือนเดิม

    การสร้าง swarm
    รันคำสั่ง docker swarm init เพื่อเปิดใช้ swarm mode ตอนนี้เราจะได้ swarm manager
    จากนั้นไปรันคำสั่ง docker swarm join ที่เครื่องอื่น ๆ เพื่อ join เข้า swarm เป็น workers
    ข้อควรระวัง
    จะต้องตั้งชื่อ hostname ให้กับเครื่องทุกเครื่องเพื่อให้มีชื่อที่แตกต่างกัน อย่าใช้ชื่อว่า ubuntu ทั้งหมด จะงง ผมเจอมาแล้ว จงแก้ไขไฟล์ /etc/hosts และ ไฟล์ /etc/hostname แล้ว reboot ก่อนเริ่มสร้าง swarm

    ผมทดสอบด้วย VM ใน Oracle VM VirtualBox อยู่ใน Windows 10 ตั้งค่า network adapter เป็น Bridge จึงใช้ IP ของที่ทำงานได้ ดังรูป


    เช่น
    เครื่องที่ 1 ให้ตั้งชื่อว่า docker-vm1 ซึ่งก็คือเครื่องที่ทำไว้ในบทความตอนที่ 1 และ 2 ต้องกลับไปเปลี่ยนชื่อ
    เครื่องที่ 2 ให้ตั้งชื่อว่า docker-vm2 ซึ่งก็คือเครื่อง ubuntu server ว่าง ๆ ตัวใหม่ในบทความตอนที่ 3 นี้ที่จะเป็น worker

    มาสร้าง two-machine cluster ให้เป็น swarm กัน
    1. ติดตั้ง docker ลงใน ubuntu server ตัวใหม่ (ชื่อเครื่อง docker-vm2)
    2. อยู่ที่เครื่องที่เป็น swarm manager (ชื่อเครื่อง docker-vm1) รันคำสั่ง

    docker swarm init

    จะได้ข้อความแจ้งว่า จะต้องใช้คำสั่งอย่างไรที่เครื่องที่จะ join เข้ามาเป็น worker (แบบ manual คือ จดบรรทัดที่ได้รับคำแนะนำเอาไว้)

    3. ไปที่เครื่อง ubuntu server ตัวใหม่นี้ พิมพ์คำสั่ง เพื่อ join เข้า swarm เป็น worker

    docker swarm join --token SWMTKN-1-5h25g0ywnp87ohk1pav8mon72zdmotqbbunj4bu88fq7sxm2go-57cqncfd2mzapxg2525q14nug 192.168.6.22:2377
    This node joined a swarm as a worker.

    หรือ

    ทำแบบใช้คำสั่งที่ซับซ้อนขึ้น ต้องใช้ข้อมูล ชื่อ username กับ เลข IP ของ swarm manager (docker-vm1) ในตัวอย่างนี้ username คือ mama และ IP คือ 192.168.6.22 โดยพิมพ์คำสั่งข้างล่างนี้ที่เครื่องที่จะเป็น worker (docker-vm2)

    $(ssh username@IP "docker swarm join-token worker" | grep token)

    4. กลับไปที่เครื่องที่เป็น swarm manager เพื่อรัน app

    cd ~/myservice
    docker stack deploy -c docker-compose.yml testlab

    5. ตรวจสอบว่า มีการสร้าง container ไว้ใน node ทั้งสอง รันคำสั่งนี้

    docker stack ps testlab

    ผลลัพธ์

    ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
    jcd1rfvnglnv testlab_web.1 woonpsu/docsdocker:part1 docker-vm1 Running Running 6 seconds ago
    lt98v35jw5y1 testlab_web.2 woonpsu/docsdocker:part1 docker-vm2 Running Running 6 seconds ago
    nz4gq3ew2f3t testlab_web.3 woonpsu/docsdocker:part1 docker-vm1 Running Running 5 seconds ago
    plnnmmmbm9hx testlab_web.4 woonpsu/docsdocker:part1 docker-vm2 Running Running 6 seconds ago
    jr5a0nhs38zf testlab_web.5 woonpsu/docsdocker:part1 docker-vm1 Running Running 6 seconds ago
    qvexlvmaw8ge testlab_web.6 woonpsu/docsdocker:part1 docker-vm2 Running Running 5 seconds ago

    เสร็จแล้วครับ ลองใช้งานจาก http://node_ip โดยแทนที่ node_ip ด้วย IP ของเครื่องที่อยู่ใน swarm cluster

    จะเห็นว่า หลังคำว่า Hostname: จะเป็นเลข container ID ที่อยู่ในเครื่อง docker-vm1 และ docker-vm2 ซึ่งเป็นการยืนยันว่า web page นี้เรียกมาจาก container ทั้ง 2 เครื่อง

    โดยใช้คำสั่งเพื่อดู container ID ที่เกิดขึ้นของแต่ละ node

    docker ps

    ดูข้อมูลของแต่ละ node ด้วยคำสั่ง (คำสั่งนี้ต้องใช้ที่ swarm manager)

    docker node ls
    docker node inspect docker-vm1 --pretty
    docker node inspect docker-vm2 --pretty

     

    เพิ่มเติม
    ขั้นตอนการเปลี่ยนชื่อเครื่องจากชื่อเดิม ubuntu เป็น docker-vm1
    mama@ubuntu:~$ sudo vi /etc/hosts
    [sudo] password for mama:
    127.0.0.1 localhost
    127.0.1.1 docker-vm1

    mama@ubuntu:~$ sudo vi /etc/hosts
    docker-vm1

    mama@ubuntu:~$ sudo reboot

     

    บันทึก output ที่ docker-vm1

    mama@docker-vm1:~$ docker swarm init
    Swarm initialized: current node (ph8gaptp7quk3cxv9lwt91c7n) is now a manager.

    To add a worker to this swarm, run the following command:

    docker swarm join --token SWMTKN-1-5h25g0ywnp87ohk1pav8mon72zdmotqbbunj4bu88fq7sxm2go-57cqncfd2mzapxg2525q14nug 192.168.6.22:2377

    To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instructions.

    mama@docker-vm1:~$ cd ~/myservice
    mama@docker-vm1:~/myservice$ docker stack deploy -c docker-compose.yml testlab
    Creating network testlab_webnet
    Creating service testlab_web

    mama@docker-vm1:~/myservice$ docker stack rm testlab
    Removing service testlab_web
    Removing network testlab_webnet

    mama@docker-vm1:~/myservice$ docker stack deploy -c docker-compose.yml testlab
    Creating network testlab_webnet
    Creating service testlab_web

    mama@docker-vm1:~/myservice$ docker stack ps testlab
    ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
    jcd1rfvnglnv testlab_web.1 woonpsu/docsdocker:part1 docker-vm1 Running Running 6 seconds ago
    lt98v35jw5y1 testlab_web.2 woonpsu/docsdocker:part1 docker-vm2 Running Running 6 seconds ago
    nz4gq3ew2f3t testlab_web.3 woonpsu/docsdocker:part1 docker-vm1 Running Running 5 seconds ago
    plnnmmmbm9hx testlab_web.4 woonpsu/docsdocker:part1 docker-vm2 Running Running 6 seconds ago
    jr5a0nhs38zf testlab_web.5 woonpsu/docsdocker:part1 docker-vm1 Running Running 6 seconds ago
    qvexlvmaw8ge testlab_web.6 woonpsu/docsdocker:part1 docker-vm2 Running Running 5 seconds ago

    บันทึก output ที่ docker-vm2

    mama@docker-vm2:~$ docker swarm join --token SWMTKN-1-5h25g0ywnp87ohk1pav8mon72zdmotqbbunj4bu88fq7sxm2go-57cqncfd2mzapxg2525q14nug 192.168.6.22:2377
    This node joined a swarm as a worker.

     

    References:
    Get Started https://docs.docker.com/get-started/

  • เตาะแตะไปกับ Docker ตอนที่ 2 Services (Scale and load-balancing)

    ในตอนนี้ เราก็จะขยับขึ้นไปอีก 1 level ใน hierachy ของ distributed application
    Stack
    Service (ในตอนนี้เราอยู่ที่นี่)
    Container

    Service 1 Service รันจาก 1 image โดยระบุ port ที่จะใช้ กำหนดจำนวน contrainer ที่จะรัน โดยที่เราสามารถเพิ่มจำนวน (Scale) service ให้รองรับโหลดมาก ๆ ได้ เราจะทำได้โดยการเขียน docker-compose.yml

    เริ่มต้นโดยการสร้างไฟล์นี้ไว้ใน directory ว่าง

    mkdir myservice
    cd myservice

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

    vi docker-compose.yml

    คัดลอกเนื้อหาจากตัวอย่าง https://docs.docker.com/get-started/part3/#your-first-docker-composeyml-file

    โดยแก้ไขในบรรทัด
    image: username/repository:tag
    ให้เป็น
    image: woonpsu/docsdocker:part1
    ดังนี้

    version: "3"
    services:
      web:
        # replace username/repo:tag with your name and image details
        image: woonpsu/docsdocker:part1
        deploy:
          replicas: 5
          resources:
            limits:
              cpus: "0.1"
              memory: 50M
          restart_policy:
            condition: on-failure
        ports:
          - "80:80"
        networks:
          - webnet
    networks:
      webnet:

    สำหรับสิ่งที่อยู่ในไฟล์ docker-compose.yml นั้น อธิบายอย่างคร่าว ๆ ก็คือจะบอกว่า ดึง image ที่เรา upload ไว้จากบทความในตอนที่แล้ว ซึ่งก็คือ woonpsu/docsdocker:part1 จะสร้าง container กี่อันจาก image นี้ และจะใช้ %CPU เท่าไร จะใช้ Port หมายเลขอะไร มี network อะไรสำหรับทำ load-balancing (a load-balanced overlay network)

    สังเกตในไฟล์ Compose จะเห็นการกำหนดค่า version: เป็น “3” คือความหมายที่เกี่ยวกับเรื่อง compatibility สรุปอย่างสั้น ๆ คือ เราจะทำต่อไปยังตัวอย่างการใช้งาน docker swarm จึงใช้ค่า version เป็น 3

    ตอนนี้ก็มารัน load-balancing กัน โดยเริ่มต้นสร้างหรือเข้าร่วม swarm

    docker swarm init

    หากไม่ run คำสั่งนี้ ก็จะพบ error “this node is not a swarm manager.”

    ตั้งชื่อ app เช่น testlab เป็นต้น แล้วพิมพ์คำสั่งดังนี้

    docker stack deploy -c docker-compose.yml testlab

    ตรวจดูรายการ

    docker stack ps testlab

    ถึงตรงนี้ เราลองไปที่ http://server_ip แล้วกด F5 ซ้ำ ๆ จะเห็นว่า หน้าเว็บที่แสดงนั้นถูกดึงมาจาก container แต่ละตัว สังเกตที่หลังคำว่า Hostname จะเป็นเลข container ID ที่ให้บริการ

    หากเราต้องการเพิ่มจำนวน replicas ก็เข้าไปแก้ไขไฟล์ docker-compose.yml แล้วรันคำสั่ง deploy อีกรอบ จะพบจำนวน container ที่เพิ่มขึ้น

    หากต้องการเลิกใช้ app ชื่อ testlab ดังนี้
    docker stack rm testlab
    หากต้องการออกจาก swarm ด้วยคำสั่ง
    docker swarm leave --force

     

    ในตอนต่อไป เราจะได้เรียนรู้การใช้งานจริง ๆ กันหละ คือรัน app เป็น swarm บน cluster ของเครื่องมากกว่า 1 เครื่อง

     

    ข้างล่างนี้คือบันทึก output ของคำสั่งที่ใช้

    mama@ubuntu:~/myservice$ docker swarm init
    Swarm initialized: current node (bph2py545b2uglv68vmy4qnno) is now a manager.

    To add a worker to this swarm, run the following command:

    docker swarm join --token SWMTKN-1-5h25g0ywnp87ohk1pav8mon72zdmotqbbunj4bu88fq7sxm2go-57cqncfd2mzapxg2525q14nug 192.168.6.22:2377

    To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instructions.

     

    mama@ubuntu:~/myservice$ docker stack deploy -c docker-compose.yml testlab
    Creating network testlab_webnet
    Creating service testlab_web

     

    mama@ubuntu:~/myservice$ docker stack ps testlab
    ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
    dqzbgtw1cv8b testlab_web.1 woonpsu/docsdocker:part1 ubuntu Running Running about a minute ago
    il7xlem822wf testlab_web.2 woonpsu/docsdocker:part1 ubuntu Running Running about a minute ago
    j1scjgeprrr2 testlab_web.3 woonpsu/docsdocker:part1 ubuntu Running Running about a minute ago
    k1qclfcosako testlab_web.4 woonpsu/docsdocker:part1 ubuntu Running Running about a minute ago
    o9plgp6ghv9f testlab_web.5 woonpsu/docsdocker:part1 ubuntu Running Running about a minute ago

     

    mama@ubuntu:~/myservice$ docker node ls
    ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS
    ftg9wrcso3tnpimg5isj1hz6j * ubuntu Ready Active Leader

     

    mama@ubuntu:~/myservice$ docker stack rm testlab
    Removing service testlab_web
    Removing network testlab_webnet

     

    mama@ubuntu:~/myservice$ docker swarm leave --force
    Node left the swarm.

     

    mama@ubuntu:~/myservice$ docker node ls
    Error response from daemon: This node is not a swarm manager. Use "docker swarm init" or "docker swarm join" to connect this node to swarm and try again.

     

    References:
    Get Started https://docs.docker.com/get-started/

  • เตาะแตะไปกับ Docker ตอนที่ 1 Containers (Build, Ship and Run)

    ผมอ่าน Get Started จาก docs.docker.com แล้วคิดว่าพอเข้าใจว่า docker ใช้งานอย่างไรมากขึ้นในแง่ความหมายของ Docker – Build, Ship, and Run Any App, Anywhere ที่เป็นจุดเด่น หลังจากอ่านจบที่ผมเขียนในตอนที่ 1 นี้ ก็น่าจะเข้าใจคำว่า Container และในตอนถัดไปก็จะนั้นจะเล่าถึงความหมายของคำว่า Service และ Stack ตามลำดับ

    ในการทดสอบเพื่อเขียนบทความ ผมได้ติดตั้ง docker บน ubuntu server 64 bit Xenial 16.04 (LTS) และรุ่นของ Docker ที่ใช้คือ Docker version 17.06.0-ce, build 02c1d87 ซึ่ง Docker Software มี 2 ชนิด คือ Community Edition (CE) และ Enterprise Edition (EE) ให้เลือกใช้

    [Installation]
    วิธีติดตั้ง Docker บน ubuntu นั้นจะมีคำแนะนำสำหรับรุ่น docker-ce คือเริ่มต้นจากการ SET UP THE REPOSITORY เสร็จแล้วจึง INSTALL DOCKER CE อย่างคร่าว ๆ ก็ใช้คำสั่งดังนี้

    curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
    sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
    sudo apt-get update
    sudo apt-get install -y docker-ce

    วิธีทำให้ไม่ต้องใส่คำว่า sudo หน้าคำสั่ง Docker ทุกครั้ง ดังนี้

    sudo usermod -aG docker ${USER}
    su - ${USER}
    id
    exit

    logout แล้ว login กลับเข้ามาใหม่ พิมพ์คำสั่ง id จะเห็นว่าอยู่ใน group docker ด้วยแล้ว

    ต่อไป Verify ว่า Docker CE ถูกติดตั้งสำเร็จโดยการรัน hello-world image

    docker run hello-world

    ตรวจสอบเวอร์ชั่น

    docker --version

    [Containers]
    ตอนนี้ก็ได้เวลาเตาะแตะแบบ docker เราจะเริ่มกันที่ส่วนล่างสุดของ hierarchy ของการสร้าง app 3 ส่วน นั่นคือ container
    Stack
    Services
    Container (เรากำลังอยู่ที่นี่)

    การสร้าง app เราจะทำ container ขึ้นมาจากสิ่งที่เรียกว่า Dockerfile คือไฟล์ที่เขียนข้อกำหนดว่า container จะมีสภาพแวดล้อมเป็นอะไรบ้าง โดยต้องเริ่มต้นจากสร้าง directory ว่าง ๆ บน host (จะเรียก ubuntu server ที่ติดตั้ง docker ไว้ว่า host) แล้วสร้างไฟล์ชื่อ Dockerfile ด้วยเอดิเตอร์ที่ถนัด เช่น vi หรือ nano เป็นต้น และถ้าภายในไฟล์นี้อ้างถึงไฟล์อื่น ๆ ก็สร้างไว้ให้ครบด้วยนะ ผมจะใช้ตัวอย่างจาก docs.docker.com ครับ

    mkdir myhello
    cd myhello

    สร้างไฟล์ชื่อ Dockerfile ด้วยเอดิเตอร์ vi ดังนี้

    vi Dockerfile

    คัดลอกเนื้อหาจากตัวอย่าง https://docs.docker.com/get-started/part2/#dockerfile

    # Use an official Python runtime as a parent image
    FROM python:2.7-slim
    
    # Set the working directory to /app
    WORKDIR /app
    
    # Copy the current directory contents into the container at /app
    ADD . /app
    
    # Install any needed packages specified in requirements.txt
    RUN pip install -r requirements.txt
    
    # Make port 80 available to the world outside this container
    EXPOSE 80
    
    # Define environment variable
    ENV NAME World
    
    # Run app.py when the container launches
    CMD ["python", "app.py"]

    ภายในไฟล์ Dockerfile มีอ้างถึงไฟล์ชื่อ requirements.txt และ app.py
    สร้างไฟล์ชื่อ requirements.txt ด้วยเอดิเตอร์ vi ดังนี้

    vi requirements.txt

    คัดลอกเนื้อหาจากตัวอย่าง https://docs.docker.com/get-started/part2/#requirementstxt

    Flask
    Redis

    แล้วสร้างไฟล์ชื่อ app.py ด้วยเอดิเตอร์ vi ดังนี้

    vi app.py

    คัดลอกเนื้อหาจากตัวอย่าง https://docs.docker.com/get-started/part2/#apppy

    from flask import Flask
    from redis import Redis, RedisError
    import os
    import socket
    
    # Connect to Redis
    redis = Redis(host="redis", db=0, socket_connect_timeout=2, socket_timeout=2)
    
    app = Flask(__name__)
    
    @app.route("/")
    def hello():
     try:
      visits = redis.incr("counter")
     except RedisError:
      visits = "<i>cannot connect to Redis, counter disabled</i>"
    
     html = "<h3>Hello {name}!</h3>" \
     "<b>Hostname:</b> {hostname}<br/>" \
     "<b>Visits:</b> {visits}"
     return html.format(name=os.getenv("NAME", "world"), hostname=socket.gethostname(), visits=visits)
    
    if __name__ == "__main__":
     app.run(host='0.0.0.0', port=80)

    ดังนั้นในตอนนี้ ใน directory ของเราจะมีไฟล์ 3 ไฟล์ คือ

    Dockerfile requirements.txt app.py

     

    ต่อไปเป็นการสร้าง image ชื่อ myhello จากไฟล์ 3 ไฟล์นั้น จะตั้งชื่อเป็นอะไรก็ได้นะ

    docker build -t myhello .

    จุด (.) หลังคำว่า myhello คือ อ้างถึงไฟล์ทุกไฟล์ใน current directory ในการสร้าง image

    ตอนนี้เราก็จะได้ docker image ชื่อ myhello อยู่ในเครื่องของเรา เรียกว่า local Docker image registry ดูรายชื่อด้วยคำสั่งนี้

    docker images

    ตัวอย่างผลลัพธ์

    REPOSITORY TAG IMAGE ID CREATED SIZE
    myhello latest 9748e0bc3640 7 seconds ago 194MB
    python 2.7-slim 4f57b96607d2 6 hours ago 182MB
    hello-world latest 1815c82652c0 4 weeks ago 1.84kB

     

    ต่อไปก็เป็นการสั่งทำงาน app ที่เราสร้างเป็น image แล้วนั้น คือ docker run
    เช่น ระบุว่าจะใช้ port หมายเลข 4000 ของ host ไปยัง port หมายเลข 80 ของ container

    docker run -p 4000:80 myhello
     * Running on http://0.0.0.0:80/ (Press CTRL+C to quit)

    ผลของการทำคำสั่ง docker run คือ เราจะได้ container ที่รันให้บริการ

    ตอนนี้ เครื่องที่ติดตั้ง docker นี้มี IP บน net เดียวกับเครื่องอื่น ๆ ก็จะเรียกดูข้อมูลทางหน้าเว็บจากเครื่องใดก็ได้ใน net นั้น เช่น http://server_ip:4000
    จะได้ผลลัพธ์

    หากในเครื่อง host ยังไม่ได้ติดตั้งพวก apache2 หรือ nginx web server อยู่ก่อน (ซึ่งพวกนี้จะมีค่า default ที่ใช้ port หมายเลข 80 สำหรับ http) แล้วหละก็ เราจะสามารถระบุว่าจะใช้ port หมายเลข 80 ของ host ไปยัง port หมายเลข 80 ของ container ได้ โดยเขียนคำสั่งเป็นแบบนี้
    docker run -p 80:80 myhello
    และเมื่อเรียกดูข้อมูลทางหน้าเว็บ ก็เขียนสั้น ๆ แบบนี้ http://server_ip ซึ่งไม่ต้องระบุ port

    แต่ตอนนี้สังเกตดูว่า เราต้องกด Ctrl + C เพื่อออกจาก app ที่รันอยู่เพื่อกลับไป command prompt เพราะว่า app ของเรารันอยู่ใน foreground

     

    ต่อไปเป็นการสั่งรัน app ใน background เหมือนกับการสั่ง service ทั่วไปรันรอให้บริการ
    (run the app in the background, in detached mode) ทำดังนี้

    docker run -d -p 4000:80 myhello

    จะได้ container ID เลขยาว ๆ หลาย ๆ ตัว และกลับออกมาที่ command prompt เลย ตัวอย่างเช่น
    773ddb78be11ec557405817ad871650e18f2ef82fbb62b512d47179de9c4486a

    ตรวจสอบว่าเรามี container ใดรันอยู่บ้าง ด้วยคำสั่ง

    docker ps

    ผลลัพธ์

    CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
    773ddb78be11 myhello "python app.py" About a minute ago Up About a minute 0.0.0.0:4000->80/tcp romantic_goldberg

    ตอนนี้ให้เราหยุดรัน app โดยการอ้างถึง CONTAINER ID แบบนี้:

    docker stop 773ddb78be11

     

    เมื่อมาถึงตรงจุดนี้ เราได้ทำขั้นตอน “Build” เรียบร้อยแล้ว ยังเหลือ “Ship” และ “Run” มาดูกันต่อ

    Ship ก็คือการที่เราจะนำ image ที่เราสร้างขึ้นนี้อัปโหลดไปไว้บน Docker’s public registry เพื่อ share image ให้ใคร ๆ ก็นำไปใช้ได้จากทุกที่และทุกเวลา จากนั้นเมื่อเราต้องการจะรัน app นี้ เราก็ไปหาเครื่อง Host มาสักตัว ติดตั้ง docker แล้ว run image ที่เราอัปโหลดไปไว้นั้น

    เรามาดูขั้นตอนการ share image ซึ่งเราจะต้องมี User ID ที่ cloud.docker.com จากนั้นใช้คำสั่ง

    docker login

    ก่อนที่เราจะอัปโหลด image ของเราขึ้นไป ให้เราทำการ Tag the image เพื่อเป็นข้อมูลสั้น ๆ ในรูปแบบ
    username/repository:tag เพื่ออธิบายหรือใส่เวอร์ชั่นของ image ก็ได้ และมีรูปแบบคำสั่งคือ
    docker tag image username/repository:tag
    ตัวอย่างเช่น

    docker tag myhello woonpsu/docsdocker:part1

    ตรวจสอบด้วยคำสั่ง

    docker image

    อัปโหลด image (เรียกวิธีการนี้ว่า Publish the image) ในรูปแบบคำสั่ง
    docker push username/repository:tag
    ตัวอย่างเช่น

    docker push woonpsu/docsdocker:part1

     

    เมื่อมาถึงตรงจุดนี้ เราได้ทำขั้นตอน “Build“, “Ship” เรียบร้อยแล้ว เหลือขั้นตอน “Run” มาดูกันต่อ

    จากนี้ไป เราก็สามารถใช้คำสั่ง docker run เพื่อดึง และ รัน app จาก image ที่ฝากไว้บน Public Registry เราจะรันที่เครื่องใด ๆ ก็ได้ (Pull and run the image from the remote repository) ด้วยคำสั่งนี้

    docker run -p 4000:80 woonpsu/docsdocker:part1

    เมื่อมาถึงตรงจุดนี้ เราได้ทำขั้นตอน “Build“, “Ship” และ “Run” เรียบร้อยแล้ว

     

    ในตอนถัดไป เราจะเรียนรู้ว่าวิธีการเพิ่มจำนวน application ของเราโดยการรัน container ในสิ่งที่เรียกว่า service
    โปรดติดตามตอนต่อไป

     

    References:
    Get Started https://docs.docker.com/get-started/
    Get Docker CE for Ubuntu https://docs.docker.com/engine/installation/linux/docker-ce/ubuntu/
    How To Install and Use Docker on Ubuntu 16.04 https://www.digitalocean.com/community/tutorials/how-to-install-and-use-docker-on-ubuntu-16-04

  • เปลี่ยน ubuntu sources.list ก่อนสร้าง image ด้วย dockerfile

    การใช้งาน docker นั้นเราสามารถใช้ image จาก docker hub หรือเราจะสร้าง image ของเราเอง ซึ่งมีหลายวิธีในการสร้าง image แบบของเราเอง (custom) วิธีหนึ่งคือการใช้ dockerfile อย่างคร่าว ๆ คือ

    mkdir ~/mydocker
    cd ~/mydocker
    touch dockerfile
    docker built -t test_app:20170713 .
    docker images

    ในไฟล์ชื่อ dockerfile นี้จะมีไวยกรณ์ประมาณนี้

    # Image tag: test_app:20170713 <– บรรทัดนี้คือ comment
    FROM ubuntu:16.04 <– บรรทัดนี้คือ ไปเอา image ชื่อ ubuntu:16.04 จาก docker hub
    RUN apt-get update <– บรรทัดนี้คือ คำสั่งบอกว่าจะติดตั้ง หลังคำว่า RUN นั่นเอง
    RUN apt-get dist-upgrade -y
    RUN apt-get install -y apache2 libapache2-mod-php7.0 php7.0
    COPY …
    ADD …
    EXPOSE …
    CMD …
    และยังมี command อื่น ๆ อีก

    ทีนี้จากการที่ต้องลองผิดลองถูกบ่อย ๆ จึงพบว่า หากเราเพิ่มคำสั่ง 2 บรรทัดนี้เข้าไปก่อนบรรทัด RUN apt-get update ก็จะทำให้เราได้ใช้ ubuntu repository ที่ต้องการแทนค่า default ที่ archive.ubuntu.com เช่นต้องการให้มาใช้ th.archive.ubuntu.com ก็เขียนคำสั่งดังนี้

    RUN sed -i 's/\/us.archive/\/th.archive/g' /etc/apt/sources.list
    RUN sed -i 's/\/archive/\/th.archive/g' /etc/apt/sources.list

    ผลลัพธ์คือ หลังจากทำคำสั่ง docker built -t test_app:20170713 . จะเห็นว่าในขั้นตอนการ build นั้นจะดาวน์โหลดไฟล์ได้รวดเร็วกว่าเดิมมาก

    จึงนำความรู้มาบอกกันครับ อ้อลืมบอกว่าบทความที่เขียนนี้ ผมทดสอบกับ docker version 17.06.0-ce ครับ

    อยากแนะนำความรู้เกี่ยวกับ docker ที่อ่านมา พบว่าน่าสนใจ ลองอ่านดูครับ อ่านง่าย

     

    บทความในต่างประเทศ

    1. How To Install and Use Docker on Ubuntu 16.04 (https://www.digitalocean.com/community/tutorials/how-to-install-and-use-docker-on-ubuntu-16-04)
    2. How to Build an Image with the Dockerfile (https://www.sitepoint.com/how-to-build-an-image-with-the-dockerfile/)
    3. Dockerfile reference (https://docs.docker.com/engine/reference/builder/)
    4. Best practices for writing Dockerfiles (https://docs.docker.com/engine/userguide/eng-image/dockerfile_best-practices/)
    5. How to update Docker image to maintain your containers secure  (https://bobcares.com/blog/update-docker-image/2/)
    6. How to upgrade docker container after its image changed
      (https://stackoverflow.com/questions/26734402/how-to-upgrade-docker-container-after-its-image-changed)
    7. Manage data in containers (https://docs.docker.com/engine/tutorials/dockervolumes/)

     

  • ELK #04

    คราวนี้มาติดตั้งบน Docker บ้าง

    1. ถ้าเครื่อง Server เป็น Ubuntu 16.04 ทำตามขั้นตอนนี้เพื่อให้สามารถใช้งาน Docker ได้
      วิธีการติดตั้ง Docker บน Ubuntu 16.04
    2. เนื่องจาก Elasticsearch 5.x ใช้ Virtual Memory มากขึ้น ลองใช้คำสั่งนี้ดูค่าปัจจุบัน
       sysctl vm.max_map_count

      ค่า Default น่าจะประมาณนี้
      vm.max_map_count = 65530 ให้ทำการเพิ่มด้วยคำสั่งนี้

      sudo -i
      sudo echo "vm.max_map_count=262144" >> /etc/sysctl.conf
      exit

      จากนั้นให้ทำการ Reboot

    3. ติดตั้ง docker image ของ sebp/elk ด้วยคำสั่ง
       sudo docker pull sebp/elk

      โดย Default จะได้ Lastest Version

    4. ใช้คำสี่งต่อไปนี้ เพื่อ Start ELK ขึ้นมา โดยเปิด port ให้ Kibana: 5601, Elasticsearch: 9200, Logstash: 5044 และทำงานเป็นแบบ Detach หรือ Background นั่นเอง
      sudo docker run -d -p 5601:5601 -p 9200:9200 -p 5044:5044 -it --name elk sebp/elk

      หรือถ้าจะใช้ Docker Compose ก็สามารถใช้งานด้วยวิธีการนี้
      เริ่มจาก ติดตั้ง Docker Compose ด้วยคำสั่ง

      sudo -i
      curl -L https://github.com/docker/compose/releases/download/1.14.0/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose
      chmod +x /usr/local/bin/docker-compose
      exit

      จากนั้น สร้างไฟล์ /path/to/your/config/elk.yml เนื้อหาดังนี้

      elk:
       image: sebp/elk
       ports:
       - "5601:5601"
       - "9200:9200"
       - "5044:5044"

      จากนั้นก็ Start

      sudo /usr/local/bin/docker-compose -f /path/to/your/config/elk.yml  up -d elk

      หากต้องการให้ container ทำการ start ทุกครั้งที่ Reboot ใช้คำสั่ง

      sudo crontab -e

      แล้วใส่บรรทัดนี้ต่อท้ายไฟล์

      @reboot /usr/local/bin/docker-compose -f /home/mama/elk.yml up -d elk
    5. ทดสอบว่า Container ที่กำลังทำงานอยู่มีอะไรบ้าง
      sudo docker ps

      วิธีดูว่า มี Container อะไรบ้าง (ทั้งที่ทำงานและไม่ทำงาน)

      sudo docker ps -a

      วิธีดูว่าเกิดอะไรขึ้นกับ Container (ในที่นี้ ชื่อ elk)

      sudo docker logs elk
    6. ถึงจุดนี้ ก็สามารถใช้งาน Kibana ทาง web url: http://your.host:5601 ได้แล้ว

     

    Reference:

    https://elk-docker.readthedocs.io/

     

  • ELK #03

    วิธีการติดตั้ง Kibana บน Ubuntu 16.04

    1. ก่อนอื่น Update
      sudo apt -y update ; sudo apt -y upgrade
    2. ติดตั้ง Java JDK
      sudo apt -y install default-jdk
    3. Download และติดตั้ง
      wget https://artifacts.elastic.co/downloads/kibana/kibana-5.4.2-amd64.deb
      sudo dpkg -i kibana-5.4.2-amd64.deb
    4. จากนั้นแก้ไขไฟล์ /etc/kibana/kibana.yml
      เพิ่มบรรทัดสุดท้าย

      server.host: "192.168.xxx.yyy"
      elasticsearch.url: "http://your.elastic.host:9200"
    5. จากนั้น Start Service
      sudo service kibana start
    6. เปิด Web Browser ไปที่
      http://192.168.xxx.yyy:5601
  • ELK #02

    ขั้นตอนการติดตั้ง Logstash บน Ubuntu 16.04

    1. ก่อนอื่น Update
      sudo apt -y update ; sudo apt -y upgrade
    2. ติดตั้ง Java JDK
      sudo apt -y install default-jdk
    3. Download และติดตั้ง
      wget https://artifacts.elastic.co/downloads/logstash/logstash-5.4.2.deb
      sudo dpkg -i logstash-5.4.2.deb
    4. Start Logstash Service
      sudo service logstash start
    5. ต่อไป สร้าง Configuration ไว้ใน /etc/logstash/conf.d/
      เช่น จะสร้าง Pipeline ที่อ่านจาก File /tmp/test.log แล้ว ส่งไปที่ Elasticsearch โดยตรง
      ให้สร้างไฟล์ /etc/logstash/conf.d/file.conf ดังนี้

      input {
              file {
                      path => "/tmp/test.log"
                      type=> "test"
              }
      }
      output {
              file {
                      path => "/tmp/output.txt"
              }
      }
      
    6. เมื่อลองใช้คำสั่ง
       echo "$(date): New World" >> /tmp/test.log
      

      ก็จะปรากฏไฟล์ /tmp/output.txt ขึ้น

    7. ต่อไป ลองเปลี่ยน Output เป็น Elasticsearch โดยการสร้างไฟล์ /etc/logstash/conf.d/es.conf
      input {
              file {
                      path => "/tmp/test.log"
                      type=> "test"
              }
      }
      output {
              elasticsearch {
                      hosts => ["http://your.elastic.host:9200"]
              }
      }
      
      
    8. เมื่อลองใช้คำสั่ง
       echo "$(date): New World" >> /tmp/test.log
      

      ก็จะปรากฏบรรทัดใหม่ใน /tmp/output.txt และ มีการเขียนไปบน Elasticsearch ด้วย

    9. ลองเปิด Web Browser แล้วใช้คำสั่งต่อไปนี้
      http://your.elastic.host:9200/_cat/indices?v
      ก็จะได้ผลลัพธ์ประมาณนี้
    10. จากนั้น วิธีที่จะแสดงผลที่เก็บไว้ใน Elasticsearch ให้เปิด URL นี้
      http://your.elastic.host:9200/logstash-2017.06.24/_search?q=*
      ก็จะได้ผลลัพธ์ประมาณนี้

    แล้วยังไง ??? รอดูตอนต่อไป

  • ELK #01

    ELK = ElasticSearch + LogStash + Kibana

    วิธีการติดตั้ง ElasticSearch บน Ubuntu 16.04

    1. ก่อนอื่น Update
      sudo apt -y update ; sudo apt -y upgrade
    2. ติดตั้ง Java JDK
      sudo apt -y install default-jdk
    3. Download และติดตั้ง
      wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-5.4.2.deb
      sudo dpkg -i elasticsearch-5.4.2.deb
      sudo update-rc.d elasticsearch defaults 95 10
    4. แก้ไขไฟล์ /etc/elasticsearch/elasticsearch.yml โดยเพิ่มบรรทัดสุดท้าย
      cluster.name: my-cluster-name
      network.host: [_site_]
      node.name: ${HOSTNAME}
    5. เริ่มทำงาน
      sudo -i service elasticsearch start
    6. ทดสอบการทำงาน โดยใช้คำสั่ง
      curl -XGET “${HOSTNAME}:9200/?pretty”
    7. ดู Log ได้ที่
      sudo tail -f /var/log/elasticsearch/my-cluster-name.log
  • การตั้งค่าให้ Android Emulator สามารถรัน google map ได้

    โดยปกติ Android Emulator ไม่สามารถรัน google map เนื่องจากไม่มีในส่วนของ google play serivce นั้นเอง (สังเกตุ ได้ว่าไม่มีแอพพลิเคชั่น google play) ซึ่งเมื่อนักพัฒนาทำการพัฒนาแอพพลิเคชั่นที่มีgoogle map และรองรันบน Android emulator  จะเกิดข้อผิดพลาดดังรูป
    1

    ในบทความนี้ขอนำเสนอวิธีการที่ทำให้ Genymotion ซึ่งเป็น Andriod  Emulator ตัวหนึ่งที่นิยมใช้กัน เนื่องจากทำงานได้รวดเร็ว และทำงานได้ดีกับ Android Studio 🙂

    โดยหลักการก็ไม่มีอะไรมาก เมื่อ Android emulator ของเราไม่มี google play service เราก็แค่ลงไปให้ซะเลย

    1. ขั้นแรก ต้องโหลดไฟล์ที่ใช้ในการติดตั้ง ดังรูป2

      โดยในส่วนของไฟล์ gapps-jb-xxxx-signed ต้องโหลดเวอร์ชั่นให้ตรงกับ android แต่ละเวอร์ชั่นที่ใช้งาน

    2. ต่อไปทำการติดตั้อง Genymotion-ARM-Translation_v1.1.zip ก่อน ซึ่งการติดตั้งก็ง่าย ๆ โดยการลากไฟล์ไปวางที่ Emulator ได้ทันที่ รอจนติดตั้งเสร็จและทำการ Restart Emulator
    3. ต่อไปก็ทำการ Gapps และ Restart Emulator อีกครั้ง เป็นอันเสร็จเรียบร้อย
    4. ลองเปิด Emulator จะพบว่ามีแอพพลิเคชั่น google play เรียบร้อยแล้ว ลองรันทดสอบแอพพลิเคชันที่มี google map ดูได้เลย

    3