Category: Linux (OS, shell script, etc)

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

    วันนี้เราจะเรียนรู้การใช้ dockerfile สร้าง image ชื่อ openldap เพื่อใช้เป็น LDAP database
    ผมทดสอบด้วย Oracle VM VirtualBox เป็น VM ที่ตั้งค่า Network adapter เป็นแบบ NAT network ที่ติดตั้ง Ubuntu 16.04 และ docker เรียบร้อยแล้ว ในตัวอย่างนี้ผมตั้งชื่อ host ว่า ldap.example.com โดยแก้ไขที่ไฟล์ /etc/hosts และ /etc/hostname ให้เรียบร้อย แล้วรีบูตเครื่องด้วย

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

     

    1.ขั้นตอนเตรียมไฟล์ที่เกี่ยวข้อง
    สร้างไดเรกทอรีของ image ที่เราจะสร้าง

    $ mkdir openldap

    สร้างไดเรกทอรีที่เก็บไฟล์ ldif (โครงสร้าง และ ตัวอย่างข้อมูล)

    $ cd openldap
    $ mkdir src

    สร้างไฟล์ ./src/create-schema.ldif ด้วยเอติเตอร์ที่ถนัด เช่น vi หรือ nano ก็ได้

    $ vi ./src/create-schema.ldif 
    # Starter kit for create user in domain dc=example,dc=com
    # Create 1st tree OU=groups
    dn: ou=groups,dc=example,dc=com
    objectClass: organizationalUnit
    ou: groups
    
    # Create sub tree OU=execs,OU=groups
    dn: ou=execs,ou=groups,dc=example,dc=com
    objectClass: organizationalUnit
    ou: execs
    
    # Create sub tree OU=staffs,OU=groups
    dn: ou=staffs,ou=groups,dc=example,dc=com
    objectClass: organizationalUnit
    ou: staffs
    
    # Create sub tree OU=students,OU=groups
    dn: ou=students,ou=groups,dc=example,dc=com
    objectClass: organizationalUnit
    ou: students
    
    # Create 2nd tree OU=people
    dn: ou=people,dc=example,dc=com
    objectClass: organizationalUnit
    ou: people

    สร้างไฟล์ ssl.ldif

    $ vi src/ssl.ldif
    dn: cn=config
    changetype: modify
    add: olcTLSCipherSuite
    olcTLSCipherSuite: NORMAL
    -
    add: olcTLSCRLCheck
    olcTLSCRLCheck: none
    -
    add: olcTLSVerifyClient
    olcTLSVerifyClient: never
    -
    add: olcTLSCertificateFile
    olcTLSCertificateFile: /etc/ssl/certs/ldap-ca-cert.pem
    -
    add: olcTLSCertificateKeyFile
    olcTLSCertificateKeyFile: /etc/ssl/private/ldap-ca-key.pem

    สร้างไฟล์ ./src/create-users.ldif

    $ vi ./src/create-users.ldif 
    # Create 1 user in tree OU=execs,OU=groups
    dn: cn=nana,ou=execs,ou=groups,dc=example,dc=com
    objectClass: inetOrgPerson
    uid: nana
    sn: Na
    givenName: Na
    cn: nana
    displayName: Na Na
    userPassword: 123456
    mail: nana@example.com
    
    # Create 2 users in tree OU=staffs,OU=groups
    dn: cn=koko,ou=staffs,ou=groups,dc=example,dc=com
    objectClass: inetOrgPerson
    uid: koko
    sn: Ko
    givenName: Ko
    cn: koko
    displayName: Ko Ko
    userPassword: 123456
    mail: koko@example.com
    
    dn: cn=momo,ou=staffs,ou=groups,dc=example,dc=com
    objectClass: inetOrgPerson
    uid: momo
    sn: Mo
    givenName: Mo
    cn: momo
    displayName: Mo Mo
    userPassword: 123456
    mail: momo@example.com
    
    # Create 2 users in tree OU=people
    dn: cn=lala,ou=people,dc=example,dc=com
    objectClass: inetOrgPerson
    uid: lala
    sn: La
    givenName: La
    cn: lala
    displayName: La La
    userPassword: 123456
    mail: lala@example.com
    
    dn: cn=lulu,ou=people,dc=example,dc=com
    objectClass: inetOrgPerson
    uid: lulu
    sn: Lu
    givenName: Lu
    cn: lulu
    displayName: Lu Lu
    userPassword: 123456
    mail: lulu@example.com

    สร้างไฟล์ ./src/create-students.ldif

    $ vi ./src/create-students.ldif 
    # Create 2 students in tree OU=students,OU=groups
    dn: cn=5310110293,ou=students,ou=groups,dc=example,dc=com
    objectClass: inetOrgPerson
    uid: 5310110293
    sn: 5310110293
    givenName: somsak
    cn: 5310110293
    displayName: somsak somsaknaja
    userPassword: 123456
    mail: 5310110293@example.com
    
    dn: cn=5410110308,ou=students,ou=groups,dc=example,dc=com
    objectClass: inetOrgPerson
    uid: 5410110308
    sn: 5410110308
    givenName: somsri
    cn: 5410110308
    displayName: somsri somsrisiya
    userPassword: 123456
    mail: 5410110308@example.com

    ต่อไปเป็นการเตรียม self-signed certificate เพื่อให้ใช้งาน LDAPS ได้

    $ sudo apt install ssl-cert
    $ mkdir cert
    $ cp /etc/ssl/certs/ssl-cert-snakeoil.pem cert/ldap-ca-cert.pem
    $ sudo cp /etc/ssl/private/ssl-cert-snakeoil.key cert/ldap-ca-key.pem
    $ sudo chmod +r cert/ldap-ca-key.pem

     

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

    $ vi dockerfile
    # Composer: Comments
    
    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 && \
    echo 'slapd slapd/root_password password 123456' | debconf-set-selections && \
    echo 'slapd slapd/root_password_again password 123456' | debconf-set-selections && \
    echo "slapd slapd/internal/adminpw password 123456" |debconf-set-selections && \
    echo "slapd slapd/internal/generated_adminpw password 123456" |debconf-set-selections && \
    echo "slapd slapd/password2 password 123456" |debconf-set-selections && \
    echo "slapd slapd/password1 password 123456" |debconf-set-selections && \
    echo "slapd slapd/domain string example.com" |debconf-set-selections && \
    echo "slapd shared/organization string example" |debconf-set-selections && \
    echo "slapd slapd/backend string HDB" |debconf-set-selections && \
    echo "slapd slapd/purge_database boolean true" |debconf-set-selections && \
    echo "slapd slapd/move_old_database boolean true" |debconf-set-selections && \
    echo "slapd slapd/allow_ldap_v2 boolean false" |debconf-set-selections && \
    echo "slapd slapd/no_configuration boolean false" |debconf-set-selections && \
    DEBIAN_FRONTEND=noninteractive apt install -y slapd
    
    # LDAP utils, self-signed certificates
    RUN apt-get install -y ldap-utils ssl-cert
    
    # 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
    
    # LDAP
    COPY ./src/*.ldif /tmp/
    ## Schema only, no user. 
    RUN service slapd start && \
     ldapadd -H ldapi:/// -f /tmp/create-schema.ldif -x -D "cn=admin,dc=example,dc=com" -w 123456
    ## Schema and add users.
    ## RUN service slapd start && \ 
    ## ldapadd -H ldapi:/// -f /tmp/create-schema.ldif -x -D "cn=admin,dc=example,dc=com" -w 123456 && \
    ## ldapadd -H ldapi:/// -f /tmp/create-users.ldif -x -D "cn=admin,dc=example,dc=com" -w 123456 && \
    ## ldapadd -H ldapi:/// -f /tmp/create-students.ldif -x -D "cn=admin,dc=example,dc=com" -w 123456
    
    EXPOSE 389 
    #CMD slapd -h 'ldap:///' -g openldap -u openldap -d 0
    
    #
    # LDAPS
    COPY ./cert/ldap-ca-cert.pem /etc/ssl/certs/
    COPY ./cert/ldap-ca-key.pem /etc/ssl/private/
    
    RUN chgrp ssl-cert /etc/ssl/private/ldap-ca-key.pem && \
     chmod g+r /etc/ssl/private/ldap-ca-key.pem && \
     adduser openldap ssl-cert
    
    RUN echo 'SLAPD_SERVICES="ldap:/// ldapi:/// ldaps:///"' >> /etc/default/slapd && \
     echo 'TLS_REQCERT never' >> /etc/ldap/ldap.conf
    
    RUN service slapd start && \
     ldapmodify -Y EXTERNAL -H ldapi:/// -f /tmp/ssl.ldif -v
    
    EXPOSE 636
    ##CMD slapd -h 'ldaps:///' -g openldap -u openldap -d 0
    
    CMD RUN ulimit -n 1024
    CMD /usr/sbin/slapd -h 'ldap:/// ldaps:/// ldapi:///' -g openldap -u openldap -d 0

     

    3.ขั้นตอนการรัน container
    สร้าง image ด้วยคำสั่งนี้

    $ docker build -t openldap .

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

    $ docker run -d -p 636:636 -p 389:389 --name openldap openldap
    $ docker ps

    อธิบายได้ดังนี้ container จะรันแบบ detach (-d) เปิด port 636 และ 389 ตั้งชื่อ(–name) ว่า openldap และรันจาก image ชื่อ openldap

    ทดสอบการนำเข้าข้อมูล ซึ่งเราจะใช้เครื่องที่กำลังทำอยู่นี้เป็น ldap client ไม่ต้องไปหาอีกเครื่องก็ได้ โดยเพิ่มแพ็กเกจ ldap-utils

    $ sudo apt install ldap-utils

    ทดสอบการเพิ่มตัวอย่างข้อมูล โดยเลือกใช้ port 389 (LDAP)

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

    ทดสอบการเพิ่มตัวอย่างข้อมูล โดยเลือกใช้ port 636 (LDAPS)

    $ ldapadd -H ldaps://ldap.example.com -f ./src/create-students.ldif -x -D "cn=admin,dc=example,dc=com" -w 123456

    จะพบข้อความว่า

    ldap_sasl_bind(SIMPLE): Can’t contact LDAP server (-1)

    ให้ทำคำสั่ง 2 บรรทัดข้างล่างนี้ เพื่อเพิ่ม certificate จาก LDAP server แล้วลองคำสั่งนั้นอีกครั้งจะทำได้

    $ openssl s_client -connect ldap.example.com:636 -showcerts </dev/null 2>/dev/null | openssl x509 -outform PEM | sudo tee /usr/local/share/ca-certificates/ldap.example.com.crt
    $ sudo update-ca-certificates

    ทดสอบค้นหาข้อมูล

    $ ldapsearch -xLLL -b "dc=example,dc=com" uid=lulu
    $ ldapsearch -xLLL -b "dc=example,dc=com" uid=5310110293

    ลบ container

    $ docker stop openldap
    $ docker rm openldap

     

    เรื่องสุดท้ายของบล็อกในวันนี้คือ ต้องการเก็บตัวอย่างข้อมูลที่เพิ่มไว้จะทำอย่างไร ทำได้โดยการสร้างที่เก็บ persistent data แบบ named volume โดยที่ oldata สำหรับข้อมูล และ olconfig สำหรับไฟล์คอนฟิกกูเรชัน

    $ docker volume create oldata
    oldata
    $ docker volume create olconfig
    olconfig

    เช็คดูรายการ volume

    $ docker volume ls
    DRIVER VOLUME NAME
    local olconfig
    local oldata

    รัน container (เขียนคำสั่งให้อยู่ในบรรทัดเดียว)

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

    อธิบายได้ดังนี้ container จะรันแบบ detach (-d) เปิด port 636 และ 389 ตั้งชื่อ(–name) ว่า openldap เก็บข้อมูลไว้นอก container เอาไว้ที่ volume ชื่อ oldata ที่ mapped ไปยัง /var/lib/ldap ใน container กับ olconfig ที่ mapped ไปยัง /etc/ldap/slapd.d ใน container และรันจาก image ชื่อ openldap

    เพิ่มข้อมูลตัวอย่าง

    $ ldapadd -H ldaps://ldap.example.com -f ./src/create-students.ldif -x -D "cn=admin,dc=example,dc=com" -w 123456

    ค้นหาข้อมูล

    $ ldapsearch -xLLL -b "dc=example,dc=com" uid=5310110293

    ลบ container เมื่อจะไม่ใช้งานแล้ว

    $ docker stop openldap
    $ docker rm openldap

    หลังจากลบ container ข้อมูลของเราจะยังคงอยู่ในที่เก็บข้อมูลแบบ volume อยู่ที่ path /var/lib/docker/volumes

    ในตอนต่อไปจะเป็นการสร้าง dockerfile เพื่อรัน phpldapadmin ใช้ในการเข้า admin ผ่านหน้าเว็บเพจ

  • เตาะแตะไปกับ Docker ตอนที่ 8 Cleanup Disk Space

    การเรียนรู้ docker เราก็จะมีการทดสอบ pull image มา แล้ว run เป็น container รวมทั้งอาจมีการสร้างพื้นที่เก็บข้อมูลที่เรียกว่า volumes (ทั้งแบบ named volume และ anonymous volume) บ่อยครั้งเมื่อเราใช้คำสั่งตรวจสอบ เราจะพบว่ามีอะไรไม่รู้หลงเหลืออยู่กินเนื้อที่ไปเยอะ

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

    $ docker ps -a

    ลบ containers ที่ไม่ใช้งานแล้ว

    $ docker ps --filter status=dead --filter status=exited --filter status=created -aq | xargs -r docker rm -v

    หมายเหตุ คำสั่งด้านบนนี้จะลบ data containers ด้วย ถ้ามีการสร้าง container ชนิดเก็บ data โปรดตรวจสอบให้ดีนะ ปัจจุบัน data container นั้น deprecated (ไม่แนะนำให้ใช้งาน)

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

    $ docker images

    ลบ images ที่ไม่ใช้งานแล้ว

    $ docker images --no-trunc | grep '<none>' | awk '{ print $3 }' | xargs -r docker rmi

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

    $ docker volumes ls

    ลบ volume ที่ไม่ถูกใช้งานโดย container ใด ๆ เลย

    $ docker volume ls -q -f dangling=true | xargs -r docker volume rm

    หรือจะใช้อีกแบบ แต่ต้องติดตั้ง jq เพิ่มด้วย

    $ sudo apt install jq
    $ docker ps -aq | xargs docker inspect | jq -r '.[] | .Mounts | .[] | .Name | select(.)'

     

    References:

  • เตาะแตะไปกับ Docker ตอนที่ 7 Manage data

    Docker ให้เราสามารถเลือกใช้วิธีการ mount data เข้าไปให้กับ container อยู่ 3 อย่างคือ
    1. Volumes
    2. Bind mounts
    3. tmpfs mounts

    Volumes จะถูกเก็บอยู่ในส่วนของ Host filesystem ที่จัดการโดย Docker เอง (อยู่ที่ /var/lib/docker/volumes)
    และนี่เป็นวิธีที่ดีที่สุดในการจัดเก็บข้อมูลที่เป็น persistent data (ตามคำบอกในเว็บเพจ docs.docker.com)

    Bind mounts จะถูกเก็บอยู่ในที่ไหนก็ได้ของ Host filesystem เป็นวิธีการที่มีมาตั้งแต่ Docker รุ่นแรก ๆ จึงมีข้อจำกัดเมื่อเทียบกับ Volumes

    tmpfs mounts จะถูกเก็บอยู่ในหน่วยความจำของ Host เท่านั้น

    อ่านรายละเอียดเพิ่มเติมได้จากที่นี่ https://docs.docker.com/engine/admin/volumes/ และ
    https://docs.docker.com/engine/admin/volumes/#more-details-about-mount-types

    ผมขอเล่าถึงตัวอย่างการใช้งาน Volumes ใน docker-compose.yml (version 2) ที่ผมได้ทำเสร็จแล้ว

    $ cat docker-compose.yml 
    version: '2'
    services:
     openldap:
     image: openldap
     container_name: openldap
     volumes:
      - ldapdatavol:/var/lib/ldap
      - ldapconfigvol:/etc/ldap/slapd.d
     ports:
      - "389:389"
      - "636:636"
    
    volumes:
     ldapdatavol:
      external: false
     ldapconfigvol:
      external: false

    อธิบายได้ดังนี้ ในไฟล์ docker-compose.yml นี้ เราจะรัน services ชื่อ openldap จาก image ที่สร้างไว้แล้วชื่อว่า openldap โดยรันเป็น container ที่ผมตั้งชื่อว่า openldap โดยจะเก็บข้อมูลไว้ถาวรที่ volume ชื่อ ldapdatavol ซึ่งจะ mapped กับ /var/lib/ldap ใน container และอีกบรรทัดคือ ldapconfigvol จะ mapped กับ /etc/ldap/slapd.d ใน container

    ถัดมาด้านล่างของไฟล์ เราจะต้องประกาศ volumes ไว้ด้วยว่า ldapdatavol ไม่ได้เป็น volume ที่สร้างไว้อยู่แล้วก่อนการัน docker-compose ด้วยการประกาศค่าว่า external: false เช่นเดียวกับ volume ชื่อ ldapconfigvol

    แต่ถ้าใช้ external: true จะหมายถึง docker-compose จะไม่สร้าง volume ให้ นั่นคือ เราได้สร้างไว้ก่อนแล้วด้วยคำสั่ง

    $ docker volume create --name ldapdatavol
    $ docker volume create --name ldapconfigvol

    เราสามารถดูรายการ volume ด้วยคำสั่งนี้

    $ docker volume ls

    และที่เก็บจริง ๆ จะอยู่ที่นี่ /var/lib/docker/volumes ใช้คำสั่งเปลี่ยนสิทธิเป็น root เข้าไปที่เก็บ volume แล้วเราจะสามารถสำรองข้อมูลนี้ได้โดยใช้คำสั่ง cp หรือ tar ได้เลย ดังนี้

    $ sudo su -
    # cd /var/lib/docker/volumes

    การใช้งาน volume แบบที่แนะนำนี้เรียกว่า named volume คือ เราตั้งเป็นชื่อตามที่เราคิดเอง ส่วนอีกแบบจะเรียกว่า anonymous นั่นคือ docker ตั้งชื่อให้เอง อันนี้ผมไม่ลงรายละเอียดครับ

    จบตอนนี้เราก็จะพอเข้าใจได้แล้วว่า หากจะเก็บข้อมูลของ app เช่นในตัวอย่างนี้คือ openldap ผมจะเลือกใช้ named volume ครับ ข้อมูลจะอยู่ถาวร เรียกว่าการทำ persistent data ในขณะที่ถ้าเราไม่เพิ่มการใช้ volume เข้ามากำหนดที่เก็บข้อมูล หากเราลบ container ก็จะเป็นการลบข้อมูลซึ่งอยู่ใน container ไปด้วย นอกจากว่าเราต้องการให้เป็นอย่างนั้นอาจเพราะว่าข้อมูลเป็นแค่ตัวอย่างไม่สำคัญอะไร ก็ไม่ต้องใช้ volume ครับ

  • date นั้นสำคัญไฉน

    ที่ Shell prompt พิมพ์คำสั่ง man date

    ได้อะไรมาไม่รู้เยอะแยะ…

    man date
    man date

    จากคู่มือจะเอารูปแบบวันที่ 12-09-2017 ตัวเลือกที่เกี่ยวข้องได้แก่ %d %D %e %F %g %G %m %y %Y เป็นต้น ลองส่งคำสั่ง

    date +"%d-%m-%Y"

    ได้ผลลัพธ์

    12-09-2017

    ตรงตามที่ต้องการ มาเขียนสคริปต์กันหน่อย อยากได้เมื่อวานทำไง วันนี้เล่น tcsh shell สร้างแฟ้ม date.tcsh ด้วย editor ที่ชื่นชอบมีข้อความว่า

    #!/bin/tcsh -f
    set tday=`date +"%d"`
    set tmonth=`date +"%m"`
    set tyear=`date +"%Y"`
    echo "Today is ${tday}-${tmonth}-${tyear}."
    set yday=`expr ${tday} - 1`
    echo "Yesterday was ${yday}-${tmonth}-${tyear}."

    ทดสอบสคริปต์ด้วยคำสั่ง

    tcsh date.tcsh

    ไม่อยากพิมพ์ tcsh ทุกครั้งเพิ่ม execution bit ด้วยคำสั่ง

    chmod +x date.tcsh

    เรียกใช้ได้โดยพิมพ์

    ./date.tcsh (อ่านว่า จุด-ทับ-เดต-จุด-ที-ซี-เอส-เอช)

    ผลลัพธ์ที่ได้

    Today is 12-09-2017.
    Yesterday was 11-09-2017.

    อยากได้เมื่อวานทำไมมันยากอย่างนี้ ฮา… ซึ่งเมื่อกลับไปอ่านคู่มือ (man date) ให้ดี..อีกครั้งจะพบว่ามีตัวเลือก

    -d, –date=STRING
    display time described by STRING, not ‘now’

    และเมื่่อเลื่อนลงมาล่างสุดจะพบว่า

    DATE STRING
    The –date=STRING is a mostly free format human readable date string such as “Sun, 29 Feb 2004 16:21:42 -0800” or
    “2004-02-29 16:21:42” or even “next Thursday”. A date string may contain items indicating calendar date, time of day,
    time zone, day of week, relative time, relative date, and numbers. An empty string indicates the beginning of the day.
    The date string format is more complex than is easily documented here but is fully described in the info documentation.

    โอ้ววว มันเขียนไว้หมดแล้ว…

    เขียนใหม่ได้ว่า
    date -d yesterday

    ได้ผลลัพธ์

    Mon Sep 11 21:43:51 +07 2017

    เปลี่ยนให้ผลลัพธ์ออกมาในรูปแบบที่ต้องการได้ด้วยคำสั่ง

    date -d yesterday +"%d-%m-%Y"

    ก็จะได้ผลลัพธ์ว่า

    11-09-2017

    แก้สคริปต์ date.tcsh

    #!/bin/tcsh -f
    set tday=`date -d today +"%d-%m-%Y"`
    set yday=`date -d yesterday +"%d-%m-%Y"`
    echo "Today is ${tday}."
    echo "Yesterday was ${yday}."

    เจ็บมาเท่าไหร่แล้วกับคำว่าไม่อ่านเอกสาร….

    ยังใส่ข้อความอื่นๆ แทน string ได้เช่น
    date -d 'tomorrow'
    date -d '-1 days ago'
    date -d '200 days'
    date -d '1000 weeks'
    date -d '30 months'
    date -d '300 years'

    เรื่องนี้สอนให้รู้ว่า บางทีเอกสารก็มีให้หมดแล้ว ไม่ต้องทำเองก็ด้ายยยยย….

    จบขอให้สนุก

    man date
    ค้นเพิ่มเติม https://www.cyberciti.biz/tips/linux-unix-get-yesterdays-tomorrows-date.html

  • วิธีการ Upload ไฟล์ไปบน Google Drive File Stream ด้วย Google Client Library for Python

    Google Drive File Stream จริงๆแล้วก็คือการเปิดให้ PC ทั้ง Windows และ Mac สามารถ Map Drive จาก Google Drive มาเป็น G:\ หรืออะไรทำนองนั้น แต่ปัจจุบัน (September 2017) บน Windows Server ซึ่งใช้ Secure Boot จะไม่สามารถติดตั้ง Client ได้ และ Ubuntu Server ก็ยังไม่มีตัวติดตั้ง ดังนั้น ในภาพของผู้ดูแลระบบ ไม่สามารถใช้ความสามารถนี้ได้ … โดยตรง

    ส่วนใน Windows Desktop ทั่วไปก็จะติดตั้งได้ แม้ว่า จากคำโฆษณา จะบอกว่าผู้ใช้สามารถใช้งานได้ แม้พื้นที่บน Local Drive ไม่เยอะ แต่เอาเข้าจริง ด้วยความสามารถที่จะใช้งาน Offline ได้บ้าง ทำให้ Client ต้อง Cache ไฟล์ที่ใช้งานด้วยเช่นกัน และหาก upload ไฟล์ขนาดใหญ่ จาก Local Drive ไปเก็บใน G:\ ข้างต้น ก็จะทำให้ต้องเสียพื้นที่ในขนาดเท่าๆกันไปด้วย เช่น ใน Local Drive มีไฟล์ที่จะ Backup ขึ้นไป ขนาด 1 GB บน C:\ เมื่อทำการ Copy ไปยัง G:\ ก็จะเสียพื้นที่อีก 1 GB ด้วยเช่นกัน

    ทางออกก็คือ ใช้ความสามารถของ Google Client Library ทำการ Upload ไฟล์ขึ้นไปโดยตรง เท่าที่ทดลองมา จะไม่ได้ Cache บน Local Drive ทำให้สามารถ Upload ไฟล์ขนาดใหญ่ได้ โดยไม่เสียพื้นที่เพิ่มแบบ Client ข้างต้น

    วิธีการใช้งาน Python เพื่อ Upload File ขึ้น Google Drive File Stream

    1. ผมเขียน Code เอาไว้ ชื่อ upload2gdrive.py ไว้บน GitHub (https://github.com/nagarindkx/google) สามารถดึงมาใช้งานได้โดยใช้คำสั่ง
      clone https://github.com/nagarindkx/google.git
      cd google
    2. สร้าง Project, Credential ตาม “ขั้นที่ 1” ในบทความ การใช้งาน Google Drive API ด้วย Google Client Library for Python ซึ่งจะได้ไฟล์ Client Secret File มา ให้แก้ไขชื่อเป็น “client_secret.json” แล้ว นำไปไว้ใน directory “google” ตามข้อ 1
    3. วิธีใช้คำสั่ง
      ดูวิธีใช้

      python upload2gdrive.py --help

      Upload ไฟล์ จาก /backup/bigfile.tar,gz

      python upload2gdrive.py --file /backup/bigfile.tar.gz

      บน Windows ก็สามารถใช้งานได้ ด้วยคำสั่ง

      python upload2gdrive.py --file D:\backup\bigfile.tar.gz

      หากต้องการระบุตำแหน่ง Folder บน Google Drive ที่ต้องการเอาไฟล์ไปไว้ ให้ระบุ Folder ID

      python upload2gdrive.py --file /backup/bigfile.tar.gz ----gdrive-id xxxxxxxbdXVu7icyyyyyy

      หากต้องการระบุ Chunk Size (ปริมาณข้อมูลที่จะแบ่ง Upload เช่น ไฟล์ 1 GB หากกำหนด Chunk Size เป็น 100MB โปรแกรมจะแบ่งข้อมูลเป็น 10 ส่วน — ขนาดที่เล็กที่สุดคือ 1 MB และค่า Default คือ 100 MB)

      python upload2gdrive.py --file /backup/bigfile.tar.gz ----gdrive-id xxxxxxxbdXVu7icyyyyyy --chunk-size 100
    4. ผลการทำงานจะประมาณนี้

      ใน Google Drive ที่กำหนด ก็จะมีไฟล์ปรากฏอยู่

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

    PS: ในบทความต่อไป จะมาอธิบายว่า เขียนขึ้นมาได้อย่างไร โปรดติดตามชม

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

    อยากลองใช้ docker แต่ยังไม่ต้องการนำ image อัปโหลดไปไว้บน docker hub จะทำอย่างไรได้มั้ย ที่นี่มีคำตอบครับ

    เราสามารถนำ docker image ที่ได้สร้างขึ้นนั้นไปเก็บไว้ในสิ่งที่เรียกว่า Docker registry ซึ่งแบ่งได้เป็น 2 อย่างคือ Public registry อยู่ที่ hub.docker.com เราจะต้องลงทะเบียนเพื่อขอมีบัญชีผู้ใช้จึงจะสามารถอัปโหลด image ไปเก็บไว้ได้ ส่วนอีกอย่างก็คือ Private (Local) registry จะเป็นการสร้างที่เก็บส่วนตัว ที่เก็บของหน่วยงาน ในบทความนี้จะสาธิตทำที่เก็บ image สำหรับทดสอบงาน

    การใช้งาน Docker public registry ต้องมี user account ที่ cloud.docker.com
    จะต้อง login ก่อนจึงจะ push image ขึ้นไปได้ เหมือนที่แสดงตัวอย่างไว้ในบล็อก “เตาะแตะไปกับ Docker ตอนที่ 1”

    $ docker login

    ตัวอย่างคำสั่ง push ที่ผมนำ image ไปเก็บไว้

    $ docker push woonpsu/docsdocker:part1

    ซึ่งเรียกใช้จากที่เครื่องใดก็ได้ ด้วยคำสั่ง pull

    $ docker pull woonpsu/docsdocker:part1

     

    แต่หากเรายังไม่พร้อมที่จะนำ image ไปไว้บนนั้น เราก็ทำ Local registry ไว้ใช้เองไปพราง ๆ ก่อน ทำได้ 2 แบบ คือ
    1. Local registry ที่ใช้งานภายในเครื่องของเราเครื่องเดียว
    2. Local registry ที่เราเปิดให้เครื่อง client อื่น ๆ เข้ามาใช้ร่วมได้

    Local registry แบบที่ใช้งานภายในเครื่องของเราเครื่องเดียว (localhost:5000)
    ใช้คำสั่งนี้เพื่อเริ่มต้นสร้าง registry container

    $ docker run -d -p 5000:5000 --restart=always --name myregistry registry:2

    จากนั้นเรา pull image สักอัน จาก hub.docker.com เช่น

    $ docker pull ubuntu:16.04

    หลังจากดัดแปลง(ไม่ทำก็ได้)ตามต้องการแล้วก็ใส่ tag localhost:5000/my-ubuntu ดังนี้

    $ docker tag ubuntu:16.04 localhost:5000/my-ubuntu
    $ docker images

    แล้วก็ push image ไปยัง local registry ซึ่งก็คือ เครื่องที่เรากำลังใช้งาน (localhost) ใช้ port หมายเลข 5000 ดังนี้

    $ docker push localhost:5000/my-ubuntu

    ซึ่งวิธีการเรียกใช้งาน image ที่เก็บไว้นั้น เป็นดังนี้

    $ docker pull localhost:5000/my-ubuntu

    ก่อนไปทำตัวอย่างถัดไปซึ่งเป็นแบบที่ 2 ให้ลบ container ชื่อ myregistry ที่ทดสอบเสร็จแล้ว ที่ต้องลบเพราะว่าใช้ port หมายเลขเดียวกัน หากใช้หมายเลข port ต่างกัน ก็ไม่ต้องลบ

    $ docker stop myregistry
    $ docker rm myregistry

     

    Local registry แบบที่เราเปิดให้เครื่อง client อื่น ๆ เข้ามาใช้ร่วมได้ (docker-registry.localdomain:5000)

    เราจะต้องเริ่มต้นที่การกำหนดชื่อเครื่อง ผมสมมติตั้งชื่อว่า docker-registry.localdomain ให้กับ host ที่ติดตั้ง docker registry ใครจะตั้งอย่างไรก็ได้ครับ

    ในบทความนี้ เนื่องจากว่า ผมจะทดสอบแบบไม่ได้ไปจด Domain Name จริงให้กับเครื่อง ผมจะต้องแก้ไขไฟล์ /etc/hosts และ /etc/hostname ดังนี้

    ที่ไฟล์ /etc/hosts ให้เพิ่มบรรทัด

    10.168.16.19 docker-registry.localdomain

    ที่ไฟล์ /etc/hostname ให้เปลี่ยนชื่อเครื่องจากเดิม มาเป็นดังนี้

    docker-registry.localdomain

    เสร็จแล้ว reboot เครื่อง

    ขั้นตอนการตั้งค่า มาดูกันครับ
    เริ่มต้นที่เครื่อง docker-registry.localdomain
    ให้ทำคำสั่งตั้งค่า TLS certificate เพราะว่าจำเป็นต้องใช้ด้วย (หากมี certificate ของจริงก็นำมาใช้แทน domain.crt และ domain.key ได้เลย)

    $ cd
    $ mkdir certs
    $ openssl req \
    -newkey rsa:4096 -nodes -sha256 -keyout certs/domain.key \
    -x509 -days 365 -out certs/domain.crt

    จะมีการถามให้เติมข้อมูล เอาคล้าย ๆ ตัวอย่างก็ได้

    Generating a 4096 bit RSA private key
    writing new private key to 'certs/domain.key'
    Country Name (2 letter code) [AU]:TH
    State or Province Name (full name) [Some-State]:SK
    Locality Name (eg, city) [ ]:HDY
    Organization Name (eg, company) [Internet Widgits Pty Ltd]:PSU
    Organizational Unit Name (eg, section) [ ]:CC
    Common Name (e.g. server FQDN or YOUR name) [ ]:docker-registry.localdomain
    Email Address [ ]:

    จะพบว่าในไดเรกทอรี certs จะเกิดไฟล์ 2 ไฟล์

    $ ls certs/
    domain.crt domain.key

    ใช้คำสั่ง docker run สร้าง container และสมมติตั้งชื่อว่า netregistry

    $ docker run -d --restart=always --name netregistry \
    -v `pwd`/certs:/certs \
    -e REGISTRY_HTTP_ADDR=0.0.0.0:5000 \
    -e REGISTRY_HTTP_TLS_CERTIFICATE=/certs/domain.crt \
    -e REGISTRY_HTTP_TLS_KEY=/certs/domain.key \
    -p 5000:5000 \
    registry:2

    ต่อไปจะเป็นการทดสอบการใช้งาน local registry
    ใส่ tag ก่อนที่จะ push ดังนี้

    $ docker tag ubuntu:16.04 docker-registry.localdomain:5000/my-ubuntu
    $ docker images

    แล้ว push image เก็บไว้ใน local registry

    $ docker push docker-registry.localdomain:5000/my-ubuntu

     

    ไปที่เครื่อง client สมมติตั้งชื่อ hostname ว่า docker-vm3
    ที่ไฟล์ /etc/hosts ให้เพิ่มบรรทัด

    127.0.1.1 docker-vm3
    10.168.16.19 docker-registry.localdomain

    ที่ไฟล์ /etc/hostname เป็นดังนี้

    docker-vm3

    เสร็จแล้ว reboot เครื่อง
    ต่อไปก็ทดสอบ pull image จาก local registry ที่ทำขึ้นนั้น

    $ docker pull docker-registry.localdomain:5000/my-ubuntu
    $ docker images

    ต่อไปก็ทดสอบ push image โดยเราก็ไปเอา image จาก hub.docker.com มาสัก 1 อัน ใส่ tag แล้ว push ดังนี้

    $ docker pull woonpsu/docsdocker:part1
    $ docker tag woonpsu/docsdocker:part1 docker-registry.localdomain:5000/helloworld
    $ docker push docker-registry.localdomain:5000/helloworld

    จะพบว่าเราสามารถ push image ไปยังเครื่อง local registry ได้ด้วย

    วิธีที่แนะนำไปแล้วข้างต้น เป็นการสร้าง Local registry ที่ไม่ได้มีความปลอดภัย เพราะว่าแค่รู้ชื่อเครื่อง รู้หมายเลข port (เลือกทดสอบกับ port 5000) ก็สามารถ push image ได้แล้ว

     

    ดังนั้นหากจะสร้าง Local registry ให้บริการ (production) เราก็ต้องทำขั้นตอนเพิ่มอีกคือต้องใช้ TLS certificate ร่วมกับ Access control

    ดังนี้

    ที่เครื่อง docker-registry.localdomain
    สร้าง username ที่มีสิทธิจะเข้ามา (access) ใช้ local registry สมมติชื่อ testuser และรหัสผ่านคือ testpassword ดังนี้

    $ mkdir auth
    $ docker run \
     --entrypoint htpasswd \
     registry:2 -Bbn testuser testpassword > auth/htpasswd
    $ cat auth/htpasswd
    testuser:$2y$05$UMOEA8bdBqSbHp/2LfiQ/uxLkf5IkXNqNE8V3Mp2IR/fRCsLXE5Q2

    รัน container ตั้งชื่อว่า privateregistry และเราจะเปลี่ยนมาใช้ port 443 ดังนี้

    $ docker run -d \
     --restart=always \
     --name privateregistry \
     -v `pwd`/auth:/auth \
     -e "REGISTRY_AUTH=htpasswd" \
     -e "REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm" \
     -e REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd \
     -v `pwd`/certs:/certs \
     -e REGISTRY_HTTP_ADDR=0.0.0.0:443 \
     -e REGISTRY_HTTP_TLS_CERTIFICATE=/certs/domain.crt \
     -e REGISTRY_HTTP_TLS_KEY=/certs/domain.key \
     -p 443:443 \
     registry:2

    ไปที่เครื่อง client ชื่อ docker-vm3

    $ docker login docker-registry.localdomain
    Username: testuser
    Password:

    ทดสอบ push image

    $ docker tag woonpsu/docsdocker:part1 docker-registry.localdomain/sawadee
    $ docker push docker-registry.localdomain/sawadee

    ลองทดสอบดูว่าหากไม่ได้ login ก็จะ push ไม่ได้

    $ docker logout docker-registry.localdomain
    $ docker push docker-registry.localdomain/sawadee
    The push refers to a repository [docker-registry.localdomain/sawadee]
    0d960f1d4fba: Preparing
    no basic auth credentials

     

    ข้อควรระวังในการทำ local registry คือ image ที่เรานำไปเก็บไว้ จะอยู่ใน container ซึ่งหากเราลบ container ด้วยคำสั่ง

    $ docker stop privateregistry
    $ docker rm privateregistry

    ก็จะเป็นการลบ image ทั้งหมด
    ดังนั้น เราจะต้องศึกษาวิธี mount volume เข้าไปใน container เพื่อให้ image ที่ push ไว้นั้น ถูกเก็บใน file system ของเครื่อง host แทน โดยเพิ่มบรรทัด -v นี้เข้าไปด้วยวางไว้ก่อนบรรทัดสุดท้าย (registry:2)

    -v /mnt/registry:/var/lib/registry \

    โดยที่ /mnt/registry คือ file system บน host และ /var/lib/registry คือไดเรกทอรีใน container

     

    ขอให้สนุกกับการทดลองเล่น docker กันนะครับ

     

    Reference:
    https://docs.docker.com/registry/deploying/
    https://docs.docker.com/registry/deploying/#restricting-access

     

     

  • ติดตั้ง Microsoft Office 2010 บน Linux Mint 18.2

         สวัสดีวันค่ะ… บล็อคนี้เราก็ยังคงอยู่กับ Linux Mint “Sonya” ที่มาพร้อมกับ Applicationพื้นฐานติดตั้งมาด้วย สำหรับคนที่ยังไม่คุ้นเคยกับ Linux ก็จะมีคำถามว่าแล้วโปรแกรมนี้ที่เคยใช้ในฝั่ง Windows มันมีให้ใช้ใน Linux มั้ย อย่างเช่น Microsoft Office อันนี้ Linux ก็มี LibreOffice ให้ใช้แทน และ LibreOffice Writer สามารถ Save เป็น นามสกุล .doc, .docx มาเปิดบน Windows ได้ แต่ Fonts อาจจะเพี้ยนๆหน่อยตอนเอามาเปิดบน Windows ก็มีทางเลือกให้เราติดตั้ง Fonts ที่ต้องการลงไป ดังภาพที่ 1

     

     

    ภาพที่1 ติดตั้ง Font บน Linux

    หรือไม่แน่ใจว่า Office ตัวอื่นจะประสบปัญหาอะไรไหมตอนเอาไปเปิดกับ Windows อยากได้โปรแกรมของ Microsoft Office ทั้งหมดเอาไปใช้เลย!! ก็ทำได้ ก่อนอื่นก็ต้องลง PlayOnLinux ซึ่งเป็นโปรแกรมที่ช่วยให้สามารถใช้โปรแกรม Windows บน Linuxได้ โดยทำตามขั้นตอนดังนี้ค่ะ

    Step1: ไปที่ Software Manager > Search Palyon… > Install > รอวนไปค่ะ ช้าเร็วขึ้นกับเน็ตด้วย ตามภาพที่ 2

    ภาพที่2 Install PlayOnLinux

    Step2: เปิดโปรแกรม PlayOnLinux ดังภาพที่ 3

    ภาพที่3 Open PlayOnLinux

    เมื่อรัน PlayOnLinux ขึ้นมา ให้กด Install ดังภาพที่ 4

    ภาพที่4 หน้าจอ PlayOnLinux 

    เลือกเมนู Office และเลือก Microsoft Office Version ที่ต้องการติดตั้ง ตามภาพที่ 5

    ภาพที่5 List Program in Office Category

    จากนั้นก็ Next Step ไปค่ะ ตามภาพที่ 6

    ภาพที่6 Installation Wizard

    ระหว่างทางนั้น ในเมื่อชีวิตเราไม่ได้โรยด้วยกลีบกุหลาบ Error ตามภาพที่ 7 ก็มา  ตั้งสติแล้วก็ไปลง winbind ซะ!!!

    ภาพที่7 Fatal Error

    กลับมาลง Office กันอีกที Again & Again(ไปฟังเพลงปลอบใจพลางนะ) ถ้าคุณได้ไปต่อมันก็จะขึ้นให้ Browse ไปยังที่เก็บไฟล์ .exe ตามภาพที่ 8 กด Open ไปอีกหน้าจอ แล้วกด Next รอจนติดตั้งเสร็จ

    ภาพที่8 Setup File

    ในที่สุดก็ติดตั้งเสร็จ จะแสดงผลลัพธ์ดังภาพที่ 9  ซึ่ง Shortcut ถูกสร้างไว้บน Desktop สามารถเรียกใช้ได้เลย ตามภาพที่ 10

    ภาพที่9 Installed Program

    ภาพที่10 Office Shortcut on Desktop

  • เปลี่ยน 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/)

     

  • การสลับภาษาด้วย “~” Linux Mint 18.2 64 bit

            สำหรับใครที่ในช่วงนี้เบื่อๆเซ็งๆระบบปฎิบัติการ Windows อยากลองอะไรใหม่ๆให้กับชีวิตบ้าง ใจก็อยากไป macOS แหละ ครั้นจะเอามาลงที่เครื่องเรา มันได้เหรอ(คิดในใจเบาๆ) ว่าแล้วก็หันไปซบอก OpenSource อย่าง linux ดีกว่า linux ก็จะประสบปัญหาการเปลี่ยนภาษาเหมือนตอนที่เราลง Windows ใหม่ๆ ต้องกด Left Alt + Shift เพื่อเปลี่ยนภาษา มันก็จะลำบากหน่อยๆ กดไปบ้างไม่ไปบ้างแต่คนที่ชินแล้วก็ปล่อยเขาไปนะค่ะ ส่วนเรายังไม่ชินปกติก็จะใช้ Grave “~” ตลอด ซึ่ง linux เดิมจะใช้ ปุ่ม Ctrl+Shift ในการเปลี่ยนภาษา สืบไปสืบมาได้ความว่า linux จะใช้ “~” แทนการอ้างอิง path home จึงไม่สามารถใช้ “~” เปลี่ยนภาษาได้ แต่สำหรับใครที่ยังไม่ชินก็สามารถติดตั้งโปรแกรมเพิ่มเติม เพื่อให้สามารถเปลี่ยนภาษาได้เนอะ

                ก่อนอื่นต้องทำการ download โปรแกรมมาติดตั้งติดตั้งในเครื่องเพื่อใช้ในการสลับภาษาโดยชื่อว่าgrave-key.tar.gz สามารถ download ได้ที่ http://noc.rmutl.ac.th/main/wp-content/plugins/download-monitor/download.php?id=29
           

    วิธีการติดตั้ง

    1. ไฟล์ที่ download มาจะมีนามสกุล .gz โดยเป็นไฟล์ zip ประเภทหนึ่งบนระบบปฎิบัติการ linux ดังนั้นก่อนการใช้งาน จึงต้องทำการ คลาย zip ก่อน โดยโปรแกรม zip จะถูกติดตั้งเป็นโปรแกรมพื้นฐานมาแล้ว จึงสามารถใช้งานได้ทันที โดยวิธีการคลายzip เข้าไปยังตำแหน่งไฟล์ที่ download คลิกขวาที่ไฟล์ แล้วเลือก “open with archive manager” โปรแกรมที่ไช้ในการคลาย zip จะถูกเปิดขึ้นมา หลังจากนั้น กด Extract แล้วเลือกตำแหน่ง เก็บไฟล์ ดังภาพที่ 1                                  ภาพที่ 1  Extract File ด้วย open with archive manager
    2. ทำการ install โปรแกรม โดยใช้ command ในส่ง install 
      • เปิดโปรแกรม terminal เข้าไปยังตำแหน่ง path ที่ไฟล์โปรแกมอยู่
      • run โปรแกรม ด้วยคำสั่ง ./script.sh
                                                               ภาพที่ 2 run โปรแกรม
    3. ตั้งค่า keyboard เพื่อให้สามารถใช้งานได้ โดยเปิดโปรแกรม Keyboard ตามขั้นตอนดังภาพที่ 3 หรือ Search คำว่ “keyboard” ตรงรูปแว่นขยายด้านบน                                                     ภาพที่ 3 Keyboard Settings
    4.  จากภาพที่ 4 เลือก Tab Layout แล้วกดปุ่ม Options
      • เลือก Layout switching (ดูภาพที่ 5)
      • ติ๊กที่ช่อง Grave switches layout หลังจากนั้น ปิดโปรแกรม ก็จะสามารถใช้ “~” ในการเปลี่ยนภาษาได้ เหมือนกับ Windows ปกติ (ดูภาพที่ 6)

    ภาพที่ 4 Keyboard Layout

    ภาพที่ 5 Layout switching

    ภาพที่ 6 Options