အခန်း ၁၇ :: Docker

အခုနောက်ပိုင်းမှာ developer တွေကို docker ကို အသုံးပြုလာကြပါတယ်။ အထူးသဖြင့် microservices တွေမှာ docker က အရေးပါလာပါတယ်။ server တစ်လုံးထဲ မတူညီ သည့် service တွေ run ဖို့ အတွက် မလွယ်ကူလှပါဘူး။

Docker

Docker ဟာ မတူညီသည့် OS နဲ့ services တွေကို လွယ်လင့်တကူ deplopy လုပ်ဖို့ အသင့်တော်ဆုံးပါပဲ။ အထူးသဖြင့် microservices တွေမှာ services တစ်ခုခြင်းဆီကို Container တည်ဆောက်ပြီး docker နဲ့ run ကြပါတယ်။

Virtual Machine

Virtual Machine နဲ့ run လို့ မရဘူးလား ဆိုတော့ ရပါတယ်။ သို့ပေမယ့် CPU , Memory တွေကို ခွဲပြီး ပေးထားပြီးတော့ အလုပ်လုပ်ပါတယ်။ storage space အစား ခွဲဝေပေးထားသည့် အတွက်ကြောင့် VM အတွက် server တစ်လုံးမှာ လိုအပ်ချက်တွေ အများကြီးရှိပါတယ်။

Container

ကျွန်တော်တို့တွေ အမြဲတန်း ကြုံနေရသည့် ပြဿနာက development စက်မှာ အလုပ်လုပ်တယ်။ production server လည်း ရောက်ရော အလုပ်မလုပ်တော့တာတွေ ကြုံခဲ့ဖူးမှာပါ။ Ubuntu မှာ ရေးထားပေမယ့် တကယ် deploy လုပ်ရသည့် OS ကတော့ CentOS ဖြစ်နေသည့် အခါမှာ လိုချင်သည့် package တွေ မရတာတွေ ဖြစ်ပါလိမ့်မယ်။ တစ်ခါတစ်လေ ubuntu version မတူလို့ package တွေ မတူတာတွေ ရှိတတ်ပါတယ်။

ဒါကြောင့် အခုနောက်ပိုင်းမှာ Docker Image ကို ပြောင်းပြီး အသုံးပြုပါတယ်။ Container ဆိုတာကတော့ Docker Image ကို docker platform ပေါ်မှာ run လို့ ရအောင် ပြောင်းလဲလိုက်တာပါ။ Docker Container မှာ ကျွန်တော်တို့ လိုချင်သည့် လုပ်ဆောင်မှုတွေ ဖြစ်သည့် OS တွေ package တွေ အကုန်ပါဝင်ပါတယ်။ လက်ရှိ OS ကို မထိခိုက်ပဲ သီးသန့် host အနေနဲ့ တည်ရှိနေပါတယ်။ ဒါကြောင့် microservices တွေ အတွက် container ကို အသုံးပြုပြီး server တစ်ခုတည်းမှာလည်း အသုံးပြုနိုင်ပါတယ်။

Install Docker

https://docs.docker.com/engine/install/ubuntu/ မှာ docker သွင်းဖို့ ကို လေ့လာနိုင်ပါတယ်။ Docker ကို Windows/Mac/Linux တို့မှာ သွင်းပြီး အသုံးပြုနိုင်ပါတယ်။

Example

docker pull ubuntu

ဆိုရင် ubuntu docker image ကို ဆွဲချလိုက်တာပါ။ စက်ထဲမှာ ubuntu image ပဲ ရှိပါသေးတယ်။ container မဖြစ်သေးပါဘူး။

docker images

အဲဒါဆိုရင်တော့ စက်ထဲမှာ ရှိသည့် images တွေ ဖော်ပြပေးမှာပါ။

Image ကို run ချင်ရင်တော့

docker run -dit -v /Users/username/shared:/var/www/sample -p 9091:80 -e LANG=C.UTF-8 -e LC_ALL=C.UTF-8 ubuntu 

ဒါဆိုရင် ubuntu image ကို container တစ်ခု ဆောက်လိုက်ပါပြီ။

-d | docker container ကို နောက်ကွယ်မှာ run ပြီး container ID ထုတ်ပြရန်
-i | Keep STDIN open even if not attached
-t | Allocate a pseudo-TTY

လက်ရှိ စက်က file ကို docker မှာ attach တွဲချင်သည့် အခါမှာ -v ကို သုံးပါတယ်။

-v [host file path]:[docker file path]
-v 9091:80

ဆိုရင် docker ထဲက port 80 ကနေ port localhost 9091 ကို ပြန် forward လုပ်ထားတာပါ။

docker port ကို လက်ရှိ os က port ကို forward လုပ်ချင်သည့် အခါမှာ -p ကို အသုံးပြုပါတယ်။

-e ကတော့ environment ပါ။

-e LANG=C.UTF-8 -e LC_ALL=C.UTF-8

အဲဒါ မပါလာခဲ့ရင် တစ်ခါတစ်လေ encoding issue တွေ ဖြစ်တတ်လို့ ထည့်ထားတာပါ။

docker ps

ဆိုရင် run ထားသည့် docker container ကို တွေ့ရမှာပါ။

Shell

docker ps နဲ့ ဆိုရင် container ID ရလာပြီ။ အဲဒါဆိုရင် shell ထဲ ဝင်လို့ရပါပြီ။

docker exec -it [containerID] /bin/bash

Container မှ image သို့

docker container တစ်ခုထဲ shell script နဲ့ ဝင်ပြီး လိုအပ်သည့် software များ ထည့်သွင်းပြီးပြီ ဆိုရင် ကျွန်တော်တို့ container ကို image ပြောင်းပါမယ်။

docker ps

နဲ့ container ID ကို အရင်ကြည့်ပါ။ ပြီးရင်

docker commit [containerID]

docker images

ခေါ်လိုက်သည့် အခါမှာတော့ REPOSITORY Tag နဲ့ image ထွက်လာပါမယ်။

docker tag [IMAGE ID] [NEW NAME]

အခု ပုံမှာတော့ hi_vim လို့ နာမည်ပေးထားလိုက်ပါတယ်။

docker stop [Container ID]

လက်ရှိ run နေသည့် container ကို ရပ်ဖို့ပါ။

docker rm [Container ID]

လက်ရှိ run ထားသည့် container ကို ဖျက်လိုက်ပါပြီ။

docker run -dit -v /Users/username/shared:/var/www/sample -p 9091:80 -e LANG=C.UTF-8 -e LC_ALL=C.UTF-8 hi_vim 

docker run တာကတော့ အရင်အတိုင်းပါပဲ။ ပြောင်းလဲ သွားတာကတော့ image name ပါ။ အခု image hi_vim နဲ့ run ထားလိုက်ပါတယ်။

ပြီးရင် docker ps ကနေ container ID ထုတ်ပါ။ docker exec -it [container id] /bin/bash နဲ့ ဝင်ပြီး သွင်းထားသည့် software တွေ package တွေ ရှိရဲ့လား စစ်ကြည့်ပါ။

Publish to Docker Hub

Image ကို လူတိုင်း သုံးနိုင်အောင် publish လုပ်ထားလို့ရပါတယ်။ နောက်ပြီး server ကနေ ဆွဲချလို့ရအောင် publish အရင် လုပ်လို့ရပါတယ်။ Docker hub မသုံးချင်ပဲ private repo အတွက် ဆိုရင် gitlab က repo ကို အသုံးပြုနိုင်ပါတယ်။

https://hub.docker.com မှာ login ဝင်ပြီး Create Repository လုပ်ပါ။

Repo name ထည့်ပြီး Create လုပ်လိုက်ပါ။

အခု ကျွန်တော်က saturngod/hi_vim repo ကို create လုပ်ထားပါတယ်။

ပြီးလျှင်

docker login

ဖြင့် docker hub ကို command line ကနေ login အရင် ဝင်ထားဖို့ လိုပါတယ်။ သတိထားရမှာက password အစား access token နဲ့ ဝင်ဖို့ recommand လုပ်ပါတယ်။ Access Token ကို ဘယ်လိုရနိုင်သလဲ ကို

https://docs.docker.com/go/access-tokens/ မှာ ရေးထားပေးပါတယ်။

အကောင့် ပြောင်းချင်ရင်တော့

docker logout
docker login

နဲ့ ပြောင်းနိုင်ပါတယ်။

docker tag [local image]:[Tag] [Repo]:[Tag]

အခု hi_vim ကို saturngod/hi_vim repo tag ပေါင်းထည့်လိုက်ပါပြီ။

docker images မှာလည်း saturngod/hi_vim ကို မြင်ရပါလိမ့်မယ်။

docker push saturngod/hi_vim:latest

ဒါကတော့ ကျွန်တော့် image ကို docker hub ပေါ် push တင်လိုက်တာပါ။

Docker hub website မှာ image တက်လာတာ တွေ့ရပါလိမ့်မယ်။

ဒါဆိုရင် ဘယ်သူမဆို

docker pull saturngod/hi_vim

ဆိုပြီး ကျွန်တော် ဖန်တီးထားသည့် docker image ကို ယူသုံးလို့ရပါပြီ။

Docker File

ပုံမှန် အားဖြင့် project တစ်ခုလုံးကို depoly လုပ်ချင်သည့် အခါမှာ ကျွန်တော်တို့တွေ Docker File ကို အသုံးပြုပါတယ်။ ကျွန်တော်တို့ project ရှိသည့်နေရာမှာ Dockerfile ဆိုပြီး empty file တစ်ခု ဖန်တီးထားပါ။

Dockerfile ထဲမှာ

FROM ubuntu:latest

WORKDIR /var/www/html

RUN apt update

RUN apt install -y tzdata
ENV TZ Asia/Yangon

RUN apt install -y software-properties-common
RUN add-apt-repository ppa:ondrej/php
RUN apt update

RUN apt install -y \
	apache2 \
	zip \
	curl \
	vim \
	unzip \
	git

RUN apt install -y php8.0 libapache2-mod-php8.0 
RUN apt install -y php8.0-mysql php8.0-cli php8.0-gd php8.0-curl php8.0-xml php8.0-mbstring

RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer

COPY . /var/www/html/
COPY .docker/production.env /var/www/html/.env
COPY .docker/vhost.conf /etc/apache2/sites-available/000-default.conf

RUN cd /var/www/html/ && composer install

RUN chown -R www-data:www-data /var/www/html && a2enmod rewrite

RUN service apache2 restart

EXPOSE 80 443

CMD ["apachectl", "-D", "FOREGROUND"]

Ubuntu image ကို ယူထားပြီး ubuntu မှာ laravel run ဖို့ လိုသည့် အဆင့်အတိုင်း ထည့်ထားပါတယ်။ Port 80 နဲ့ 443 ပဲ​ access လုပ်ခွင့်ပေးထားပါတယ်။​ WORKDIR ကတော့ docker exec ကနေ run ရင် ရောက်နေမယ့် directory ပါ။ ဥပမာ docker exec -it <containerID> ls ဆိုရင် directory list ပြလာပါမယ်။

.docker/vhost.conf က

<VirtualHost *:80>
    DocumentRoot /var/www/html/public

    <Directory "/var/www/html/public">
        AllowOverride all
        Require all granted
    </Directory>

</VirtualHost>

production.env ကတော့ laravel က .env file ပါ။ production အတွက် config တွေ ထည့်ထားတာပါ။

အခု DockerFile ရပြီ ဆိုရင် docker image ဆောက်လို့ရပါပြီ။​ Docker Hub မှာ repo တစ်ခုဆောက်ပါ။ ပြီးရင်

docker build -t saturngod/empty-laravel:1.0 .

ကျွန်တော်က empty-laravel ဆိုပြီး repo ဆောက်ထားပါတယ်။ အခု version 1.0 ကို တင်ပါမယ်။

docker push saturngod/empty-laravel:1.0

ဒါဆိုရင် laravel အတွက် docker image တစ်ခု ရသွားပါပြီ။ proudction မှာ image ကို pull ဆွဲပြီး အသုံးပြုရုံပါပဲ။

Docker Compose

Docker compose ဟာ docker file ကို testing လုပ်တာ ဖြစ်ဖြစ် docker run ကို ခဏ ခဏ​ ပြန်ရေးနေမယ့် အစား docker-compose.yml ဖြင့် လိုချင်သည့် docker တွေ ကို တစ်ခါတည်း တည်ဆောက်နိုင်ပါတယ်။

အခု docker-compose.yml ဖန်တီးပါမယ်။

version: '3.8'

services:
    app:
        build:
            context: .
            dockerfile: Dockerfile
        image: 'store.dev/laravel'
        container_name: store-laravel-app
        ports:
            - "9980:80"
        networks:
            - laravel-store

networks:
    laravel-store:
        driver: bridge

docker compose version 3.8 standard ကို လိုက်နာထားပြီးတော့ docker image ကို Dockerfile ကို သုံးထားတယ်။ image name ကို store.dev/laravel ပေးထားတယ်။ container_name ကို store-laravel-app ပေးထားပါတယ်။ Docker Container က Port 80 ကို port 9980 ကနေ access လုပ်ခွင့်ပေးထားတယ်။ network ကို bridge သုံးထားပါတယ်။

Dockerfile ကို မသုံးပဲ​ image ကိုလည်း အသုံးပြုနိုင်ပါတယ်။

version: '3.8'

services:
    app:
        build:
            context: .
            dockerfile: Dockerfile
        image: 'store.dev/laravel'
        container_name: store-laravel-app
        ports:
            - "9980:80"
        networks:
            - laravel-store
        depends_on:
            - mysql
    mysql:
        image: 'mariadb:latest'
        container_name: store-laravel-db
        restart: unless-stopped
        ports:
            - "3307:3306"
        environment:
            MYSQL_DATABASE: ${DB_DATABASE}
            MYSQL_ROOT_PASSWORD: ${DB_PASSWORD}
            MYSQL_PASSWORD: ${DB_PASSWORD}
            MYSQL_USER: ${DB_USERNAME}
            MYSQL_ALLOW_EMPTY_PASSWORD: 'yes'
        volumes:
            - ./database/dbdata:/var/lib/mysql
        networks:
            - laravel-store

networks:
    laravel-store:
        driver: bridge

ဒါဆိုရင် dependency က mysql ဖြစ်သည့်အတွက်ကြောင့် mariadb container ပါ ပါဝင်လာမှာဖြစ်ပါတယ်။

volumes ကတော့ docker နဲ့ ကိုယ့် စက် နဲ့ ချိတ်ထားသည့် သဘောပါ။ mysql နဲ့ app ကို network အတူတူ သုံးထားသည့် အတွက်ကြောင့် internal network ထဲမှာလို ဖြစ်ပါလိမ့်မယ်။ app ကနေ database container ကို လမ်းပြီး ခေါ်လို့ရမှာပါ။

app container ကနေ mysql container ကို port 3306 ပဲ​ သုံရမှာပါ။

docker run နေသည့် host ကနေ mysql container က mysql ကို သုံးချင်ရင်တော့ port 3307 နဲ့ ချိတ်ရမှာပါ။

.env ထဲမှာ

DB_CONNECTION=mysql
DB_HOST=mysql
DB_PORT=3306
DB_DATABASE=laravel
DB_USERNAME=root
DB_PASSWORD=

လို့ update လုပ်ပေးလိုက်ပါ။ production.env မှာလည်း update လုပ်ပေးဖို့ လိုပါမယ်။

docker exec -it store-laravel-app php artisan migrate

store-laravel-app ကတော့ container name ပါ။ laravel ရဲ့ database migration code ကို run လိုက်တာပါ။

အခုဆိုရင် docker အကြောင်းအနည်းငယ်သိလောက်ပြီး ဘာလို့ အသုံးပြုလဲ ဆိုတာ သဘောပေါက်လောက်ပါပြီ။

Orchestration

Docker ကို production မှာ run ဖို့ Orchestration platform လိုပါတယ်။ လူသုံးများတာကတော့ Kubernetes ပါ။ K8s လို့လဲ အတိုရေးပါတယ်။ Kubernetes အပြင် Docker Swarm ရှိပါတယ်။ ​

Kubernetes ကို အသုံးပြုဖို့ run ထားသည့် platform ရှိဖို့လိုပါတယ်။​ လက်ရှိ လူသုံးများတာတွေကတော့

  • Digital Ocean Kubernetes
  • Google Kubernetes Engine (GKE)
  • Amazon Elastic Kubernetes Service (EKS)
  • Azure Kubernetes Service (AKS)

Kubernetes ဟာ Auto Scaling အပြင် zero downtime အတွက်ပါ အဆင်ပြေပါတယ်။ Kubernetes အကြောင်းဖော်ပြဖို့ အတွက် သီးသန့် စာအုပ်တစ်အုပ်စာလောက် ရှိသာဖြစ်လို့ နောက်ပိုင်း လိုအပ်ရင် ကိုယ်တိုင် ဆက်လေ့လာဖို့ လိုပါတယ်။ Kubernetes ဟာ configuration တွေက docker လိုမျိုး အများကြီး လေ့လာဖို့ လိုအပ်သလို production သွားဖို့အတွက် သီးသန့် platform လိုအပ်ပါတယ်။ အခု အခါမှာ Kubernetes ကို ပြည်တွင်းက company တွေ အသုံးပြုမှုကတော့ နည်းပါးပါသေးတယ်။ Digital Ocean မှာ Auto Scaling လိုအပ်ရင်တော့ Kubernetes ကို အသုံးပြုသင့်ပါတယ်။