Phần 1 – Docker cho người mới bắt đầu
Trong phần 1 chúng ta đã phần nào nắm sơ qua về cách hoạt động cũng như cách triển khai môi trường thông qua các image. TIếp tục trong phần này, chúng ta sẽ tìm hiểu về các bước để tạo một image với các thành phần cần thiết cho project.
Một image trong Docker được tạo thành từ các lớp layer, các layer này về bản chất là những thư mục core của hệ điều hành Linux nhưng chúng chỉ chứa các file cần thiết của các thành phần mà chúng ta cài đặt thêm, để khi ghép vào với nhau sẽ tạo nên một môi trường hoàn chỉnh với các package cần thiết cho project
Có 2 cách để tạo ra 1 image, bạn có thể build automatic từ Dockerfile hoặc build bằng tay bằng cách run 1 container, cài đặt các package và pull nó lên Dockerhub.
1. Build automatic từ Dockerfile
Trước hết, để viết được một Dockerfile hoàn chỉnh, các bạn cần hiểu được các command của Dockerfile:
- FROM: Là base image để chúng ta tiến hành build một image mới. Command này phải được đặt trên cùng của Dockerfile
- MAINTAINER: Command này là tùy chọn, có thể có hoặc không. Nó chưa thông tin của người tiến hành xây dựng lên images.
- RUN: Sử dụng khi muốn thực thi một command trong quá trình build image
- ADD: Copy một file từ host machine tới docker image. Có thể sử dụng URL cho tệp tin cần copy, khi đó docker sẽ tiến hành tải tệp tin đó đến thư mục đích.
- ENV: Định nghĩa các biến môi trường
- CMD: Sử dụng khi muốn thực thi (execute) một command trong quá trình build một container mới từ docker image
- ENTRYPOINT: Định nghĩa những command mặc định, cái mà sẽ được chạy khi container running.
- WORKDIR: Định nghĩa directory cho CMD
- USER: Đặt user hoặc UID cho container được tạo bởi image
- VOLUME: Cho phép truy cập / liên kết thư mục giữa các container và máy chủ (host machine)
Tiến hành tạo Dockerfile:
touch Dockerfile
# Extend từ image php phiên bản 7.1.2 FROM php:7.1.2 MAINTAINER Chungpt <it.chungpt1291@gmail.com> # Thư mục làm việc mặc định WORKDIR /app # Chạy command cài đặt RUN apt-get update RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer RUN apt-get install zlib1g-dev && docker-php-ext-install pdo pdo_mysql zip # Copy thư mục và file từ host vào image ADD helpers /home/helpers/ ADD start.sh /home/ RUN chmod +x /home/start.sh # Public port 80 EXPOSE 80 # Chạy file start.sh CMD ["/home/start.sh"]
Tạo file functions.sh trong thư mục helpers
touch helpers/functions.sh
#!/bin/bash HOME=/home appendToFileOnLine() { sed -i "$1s,.*,$2," $3 } appendToFile() { echo $1 >> $2 } appendAfterStringWithString() { sed -i "/$1/a \\$2\\" $3 } appendAfterStringWithFileContent() { sed -i "/$1/r $2" $3 } searchStringAndReplaceWith() { sed -i "s/$1/$2/g" $3 } clearCurrentFolder() { find . -mindepth 1 -delete rm -rf ./* } setUpMySQL() { source $HOME/helpers/mysqlConfig.sh #configure env file searchStringAndReplaceWith "DB_HOST=127.0.0.1" "DB_HOST=${MYSQL_CONFIG[DB_HOST]}" .env searchStringAndReplaceWith "DB_DATABASE=homestead" "DB_DATABASE=${MYSQL_CONFIG[DB_DATABASE]}" .env searchStringAndReplaceWith "DB_USERNAME=homestead" "DB_USERNAME=${MYSQL_CONFIG[DB_USERNAME]}" .env searchStringAndReplaceWith "DB_PASSWORD=secret" "DB_PASSWORD=${MYSQL_CONFIG[DB_PASSWORD]}" .env }
Tạo file mysqlConfig.sh trong thư mục helpers
#!/bin/sh declare -A MYSQL_CONFIG MYSQL_CONFIG[DB_HOST]="mysql" MYSQL_CONFIG[DB_DATABASE]="laravelApp" MYSQL_CONFIG[DB_USERNAME]="laravelDbUser" MYSQL_CONFIG[DB_PASSWORD]="laravelDbPass!"
Tạo file start.sh
#!/bin/bash source /home/helpers/functions.sh if [ ! -f artisan ]; then echo "Dir does not contain artisan, create Laravel project" #clear any file or hidden file in special for macOs users .DS_STORE clearCurrentFolder #add compooser dependecies composer create-project laravel/laravel ./ --prefer-dist setUpMySQL fi composer update #start project php artisan serve --port=80 --host=0.0.0.0
Cấu trúc thư mục sau khi làm xong các bước:
Tiến hành build image
Như vậy chúng ta đã tạo được image laravelenv-automatic-build của mình. Tiếp đến chúng ta sẽ chạy image này để tạo ra 1 container dùng để dev Laravel, với image này chúng ta sẽ chỉ khởi chạy, mọi việc từ download source Laravel, lib Composer, … sẽ được tự động chạy khi khởi tạo container.
docker run -itd -e MYSQL_ROOT_PASSWORD=rootPass123! -e MYSQL_DATABASE=laravelApp -e MYSQL_USER=laravelDbUser -e MYSQL_PASSWORD=laravelDbPass! --name mysql mysql &&
docker run -itd -v $(pwd):/app -p 80:80 --link mysql:lmysql --name laravel_application laravelenv-automatic-build
Kiểm tra lại thành quả
2 container là laravel và mysql đã được tạo, thư mục của bạn đã được setup đầy đủ các thành phần của laravel, và truy cập http://localhost/ xem site đã hoạt động hay chưa. Lưu ý lần đầu chạy image sẽ mất chút thời gian vì script sẽ phải clone Laravel frame work và download các thư viện Composer về, trong lúc đó hãy tìm cho mình 1 cốc cafe nhé 😀
2. Build image thủ công
Qua phần đầu chúng ta có thể thấy việc build tự động từ Dockerfile sẽ rất dễ dàng trong việc tùy biến các thành phần trong image, nhưng nếu không biết các command run trong script có hoạt động đúng hay không thì sao? Việc này chúng ta có thể build 1 cách thủ công, nó tương tự như việc cài đặt server truyền thống, truy cập và run command.
Trong phần này mình sẽ chọn image ubuntu:latest để demo vì đã quen với các cài đặt trên ubuntu, nếu quen dùng Distro khác bạn có thể search trên DockerHub, đủ cả.
Pull image ubuntu:latest (thời điểm viết bài nó tương ứng với version 16.04)
docker pull ubuntu
Khởi chạy và truy cập vào container
docker run -itd -p 8080:80 –name ubuntu_demo ubuntu && docker exec -it ubuntu_demo bash
Thử cài nginx
apt-get update
apt-get install -y nginx
service nginx restart
Sau khi khởi động lại nginx, port 80 của container này sẽ được expose ra port 8080 của host machine. Chúng ta sẽ vào http://localhost:8080 để kiểm tra
Tiếp theo chúng ta sẽ tiến hành push image này lên DockerHub, để làm được bước này trước hết bạn phải có tài khoản DockerHub và login trên máy
docker login -u <tên tài khoản>
Commit và push image lên DockerHub
Như vậy, những lần sau khi cần chúng ta sẽ chỉ phải pull image này về và chạy, rất tiện phải ko 😀