Chia nhỏ ứng dụng của bạn thành các Service Docker

Khi phân phối các ứng hoàn thành, từng phần của ứng dụng đó ở dạng sản phẩm gọi nó là các service (dịch vụ), hãy nhớ lại ví dụ của phần trước bạn đã cài đặt một ứng dụng Wordpress, hãy xem nó để trang web đó chạy được bạn đã tạo ra những thành phần gì:

  • Một container chạy HTTPD Apache là webserver.
  • Một container chạy PHP để thi hành code các file PHP.
  • Một container chạy MySQL làm CSDL cho trang web.

Những thành phần này khi phân phối ứng dụng chúng đều được gọi là các dịch vụ service. Như vậy các service thực chất là các container chạy đáp ứng chức năng thành phần tạo nên ứng dụng. Bạn cần hiểu sơ qua về khái niệm này vì ta sẽ sử dụng nó trong docker-compose giúp tạo ra các service trên một cách tự động.

Docker Compose với file docker-compose.yml

File docker-compose.yml gần giống ý nghĩa với file Dockerfile đã tìm hiểu trong Sử dụng Dockerfile, là một file text, viết với định dạng YAML (Ain’t Markup Language, đọc nhanh định dạng Định dạng YML) là cấu hình để tử đó lệnh docker compose sinh ra và quản lý các service (container), các network, các ổ đĩa ... cho một ứng dụng hoàn chỉnh.

Lệnh docker-compose

Về nội dung bên trong file docker-compose.yml sẽ tìm hiểu phía sau, giờ giả sử đang có file này, từ thư mục chứa file này gõ lệnh docker-compose với tham số phù hợp để thi hành những tác vụ như:

  • Tạo và chạy các thành phần định nghĩa trong docker-compose.yml (các dịch vụ, image, container, mạng, đĩa ...).
    docker-compose up
  • Dừng và xóa: image, container, mạng, đĩa tạo ra bởi docker-compose up
    docker-compose down
  • Theo dõi Logs từ các dịch vụ
    docker-compose logs [SERVICES]
  • Ngoài ra còn có các lệnh nhỏ khác như exec ps restart ... sẽ tìm hiều dần khi cần dùng đến.

Nội dung - Bài thực hành với docker-compose

Trong phần này, cơ bản thực hiện lại ví dụ ở phần Network, cài đặt PHP, APACHE, MYSQL, MEMCACHE, WORDPRESS với Docker nhưng sẽ sử dụng đến kỹ thuật triển khai product với docker-compose.yml, kết quả của ví dụ này đó là:

  • Tạo được image chứa Server Memcache để sử dụng cached dữ liệu cho PHP cũng như SESSION PHP
  • Tạo được một image chạy HTTPD APACHE httpd, cài và cấu hình lại phù hợp với ứng dụng web Wordpress, đặt tên là w-httpd:version2
  • Tạo được một image chạy PHP-FPM, đã cấu hình lại: đặt tên image là w-php:version2
  • Tạo được file docker-compose.yml nó thiết lập để tạo ra các dịch vụ: chạy Apache, PHP từ 2 image trên, tạo dịch vụ chạy MySQL, tạo network để nối các dịch vụ trên vào, ánh xạ thư mục web chứa code WordPress vào dịch vụ Apache và PHP.
  • Chạy docker-compose để chạy các dịch vụ, tiến hành cài đặt Joomla: Có một website chạy Joomla!

Bây giờ sẽ tiến hành từng bước một để có được kết quả trên!. Trước tiên tạo ra một thư mục đặt tên là appproject nơi đó lưu các file cấu hình, dữ liệu của dự án trên.

Tạo Image chạy Apache HTTPD

Tạo thư mục appproject/httpd để lưu dữ liệu. Image này xây dựng từ image cơ sở httpd:latest, chỉnh sửa lại httpd.conf, cài đặt thêm htop, vim. Trước tiên chạy lệnh sau để lấy ra file httpd.conf nằm trong image httpd:latest để mà chỉnh sửa.

Chuẩn bị dữ liệu

docker run -it --rm -v /mycode/:/home/conf  httpd cp conf/httpd.conf /home/conf/httpd.conf

Như phần trước, lệnh trên chạy httpd:latest, chạy xong xóa luôn container. Khi chạy nó copy httpd.conf trong container ra thư mục host /mycode/ (bạn có thể đặt thư mục khác của bạn).

Sau lệnh này bạn có file /mycode/httpd.conf, hãy copy nó vào dự án tại appproject/httpd/httpd.conf, mở file này ra và chỉnh sửa các nội dung, bỏ comment # để nạp các module cần thiết như:

LoadModule proxy_module modules/mod_proxy.so                # hỗ trợ proxy
LoadModule proxy_fcgi_module modules/mod_proxy_fcgi.so      # để gọi PHP qua Proxy
LoadModule deflate_module modules/mod_deflate.so            # để apache nén dữ liệu trả về
LoadModule rewrite_module modules/mod_rewrite.so            # để sử dụng .htaccess, rewrite url
LoadModule ssl_module modules/mod_ssl.so                    # để hỗ trợ SSL (https, port 443)

Include conf/extra/httpd-vhosts.conf                        # để nạp các Virtual Host từ file httpd-vhosts.conf

#Thêm vào
AddHandler "proxy:fcgi://php-product:9000" .php             # để chạy Script PHP qua Proxy

Tạo file appproject/httpd/httpd-vhosts.conf và cập nhật nội dung sau, để tạo ra một HOST chạy với domain mywordpressblog.com cổng 80, thư mục web là /home/sites/default/

<VirtualHost *:80>
    ServerName mywordpressblog.com
    ServerAdmin xuanthulab.net@gmail.com
    DocumentRoot /home/sites/default/
    CustomLog /dev/null combined
    #LogLevel Debug
    ErrorLog /home/sites/default/error.log
    <Directory /home/sites/default/>
        Options -Indexes -ExecCGI +FollowSymLinks -SymLinksIfOwnerMatch
        DirectoryIndex index.php index.html
        Require all granted
        AllowOverride None
    </Directory>
</VirtualHost>

Tạo file index.html

<!DOCTYPE html>
<html>
<head> <meta charset="UTF-8"><title>TEST HTML APACHE</title> </head>
<body>
    <h1>Apache HTTML đang chạy ...</h1>
</body>
</html>

Tương tự tạo một file index.php

<?php
    phpinfo();

File Dockerfile để tạo Image Apache

Sau khi chuẩn bị dữ liệu trên, tạo file appproject/httpd/Dockerfile với nội dung sau:

FROM httpd:latest

# Cập nhật và cài đặt vim, htop

RUN apt-get update -y \
    && apt-get install vim -y \
    && apt-get install htop \
    && rm -rf /var/lib/apt/lists/*

# Copy các file dữ liệu, cấu hình vào image

ADD ./index.html /home/sites/default/index.html
ADD ./index.php /home/sites/default/index.php
ADD ./httpd.conf /usr/local/apache2/conf/httpd.conf
ADD ./httpd-vhosts.conf /usr/local/apache2/conf/extra/httpd-vhosts.conf

# Mở cổng 80, 443 trên network container nối vào

EXPOSE 80 443

CMD [ "httpd-foreground"]

Đang ở thư mục httpd gõ lệnh tạo để Tạo image từ Dockerfile

docker build -t httpd:version2 --force-rm -f Dockerfile .    # tạo image từ Dockerfile
docker save --output httpd.tar httpd:version2                # lưu image ra file (để gộp layer)
docker image rm httpd:version2                               # xóa image
docker load -i httpd.tar                                     # nạp lại image từ file

Đến đây đã có image chứa APACHE HTTPD với config lại như trên, có thể kiểm tra chạy thử nhanh bằng lệnh:

docker run -it --rm -p 3456:80 httpd:version2 # container tự xóa khi kết thúc

Truy cập http://localhost:3456http://localhost:3456/index.html để kiểm tra.

proxy error

Có thông báo lỗi vì chạy mà chưa có PHP (container php-product)

Tạo Image chạy PHP-FPM

Tạo thư mục appproject/php để lưu dữ liệu. Image này xây dựng từ image cơ sở php:7.3-fpm

Chuẩn bị dữ liệu

Trích xuất php.ini từ image php:7.3-fpm.

docker run -it --rm -v /mycode/:/home/  php:7.3-fpm cp /usr/local/etc/php/php.ini-production /home/php.ini

Copy file php.ini vào thư mục appproject/php/php.ini. Mở file ra và chỉnh sửa các thiết lập:

short_open_tag = On
expose_php = Off

; THIẾT LẬP PHP SESSION DÙNG MEMCACHED
session.save_handler = memcached
session.save_path = "c-memcached01:11211"
memcached.sess_locking = 0
memcached.sess_prefix = 'memc.sess.'

; THIẾT LẬP OPCACHE NẾU CÓ DÙNG (cache mã nguồn PHP)
; zend_extension=opcache.so;
; opcache.interned_strings_buffer=4
; opcache.max_accelerated_files=2000
; opcache.memory_consumption=64
; opcache.revalidate_freq=2
; opcache.fast_shutdown=0
; opcache.enable_cli=0
; opcache.interned_strings_buffer=4
; opcache.max_accelerated_files=2000
; opcache.memory_consumption=64
; opcache.revalidate_freq=2
; opcache.fast_shutdown=0
; opcache.enable_cli=0

File Dockerfile để tạo Image PHP

Tạo ra file appproject/php/Dockerfile với nội dung sau:

FROM php:7.3-fpm

# cài đặt và kích hoạt opcache, mysqli, pdo_mysql, memcached

RUN apt-get update -y \
    && apt-get install libzip-dev zip libmemcached-dev  -y \
    && apt-get install vim -y \
    && apt-get install htop \
    && docker-php-ext-configure opcache --enable-opcache \
    && docker-php-ext-install zip opcache \
    && docker-php-ext-configure opcache --enable-mysqli \
    && docker-php-ext-install mysqli \
    && docker-php-ext-configure opcache --enable-pdo_mysql \
    && docker-php-ext-install pdo_mysql \
    && pecl install memcached \
    && rm -rf /var/lib/apt/lists/*

ADD ./php.ini /usr/local/etc/php/php.ini

EXPOSE 9000

# CMD [ "httpd-foreground"]

Đang ở thư mục php gõ lệnh tạo để Tạo image từ Dockerfile, đặt tên image này là php:version2

docker build -t php:version2 --force-rm -f Dockerfile .    # tạo image từ Dockerfile
docker save --output php.tar php:version2                  # lưu image ra file (để gộp layer)
docker image rm php:version2                               # xóa image
docker load -i php.tar                                     # nạp lại image từ file

Chuẩn bị file my.cnf cho MySQL

Ở đây ta chuẩn bị dữ liệu để xây dựng container MySQL, tiến hành trích xuất file my.cnf có trong mysql:latest ra:

docker run -it --rm -v /mycode/:/home/  mysql:latest cp /etc/mysql/my.cnf /home/my.cnf

Sau lệnh này, hãy copy file my.cnf vào thư mục /mycode/db/my.cnf ( nhớ thư mục này sau này sẽ dùng để ánh xạ dữ liệu vào container), mở file này ra thêm vào nội dung:

[mysqld]
default-authentication-plugin=mysql_native_password

Biên tập docker-compose.yml

Đến đây bạn có 2 image custome lại là php:version2, httpd:version2 giờ ta sẽ tiến hành các bước biên tập ra file docker-compose.yml để dùng với lệnh docker-compose.

Tạo ra file này ở đường dẫn appproject/docker-compose.yml, dùng một trình soạn thảo bất kỳ tiến hành biên tập nội dung. Mục đích trong trường hợp này của file docker-compose.yml là: tạo ra 4 dịch vụ gồm: máy chủ HTTP, PHP, máy chủ MySQL, máy chủ Memcached và chúng được nối vào cùng một mạng.

Nội dung và ý nghĩa các dòng viết trong file này được giải thích trong các comment, bạn có thể chỉnh lại cho phù hợp với mục đích của mình:

# VIẾT THEO CÚ PHÁP YAML, CHÚ Ý CHÍNH XÁC KHOẢNG TRẮNG ĐẦU CÁC DÒNG

version: "3"                      # chọn viết theo bản 3 docs.docker.com/compose/compose-file/

services:                         # CÁC DỊCH VỤ (CONTAINER) NĂM TRONG services

pro-memcached: # (((1))) BẮT ĐẦU TẠO DỊCH VỤ THỨ NHẤT image: "memcached:latest" # Image tạo ra dịch vụ container_name: c-memcached01 # Tên container khi chạy restart: always hostname: memcached networks: - my-network # nối vào mạng my-network (tạo mạng này ở dưới) command: - "--conn-limit=2048" # Giới hạn kết nối là 2048 - "--memory-limit=2048" # Giới hạn cho phép dùng tới 4096 MB bộ nhớ làm cache
xtlab-apache: # (((2))) TẠO DỊCH VỤ HTTPD image: "httpd:version2" # sử dụng image custome lại ở trên để tạo container container_name: c-httpd01 # tên khi chạy container HTTPD restart: always hostname: httpd01 networks: - my-network ports: - "8080:80" # Mở cổng 8080 public, ánh xạ vào 80 - "443:443" volumes: # Ánh xạ thự mục vào container - dir-site:/home/sites/ # Bind ổ đĩa - dir-site
xtlab-mysql: # (((3))) TẠO DỊCH VỤ MYSQL image: "mysql:latest" container_name: mysql-product restart: always hostname: mysql01 networks: - my-network environment: MYSQL_ROOT_PASSWORD: abc123 #Thiết lập password volumes: - /mycode/db:/var/lib/mysql # thư mục lưu DB - /mycode/db/my.cnf:/etc/mysql/my.cnf # ánh xạ file cấu hình
xtlab-php: # (((4))) TẠO DỊCH VỤ PHP image: "php:version2" container_name: php-product # tên container hostname: php01 restart: always networks: - my-network volumes: - dir-site:/home/sites/ # Bind ổ đĩa - dir-site
networks: # TẠO NETWORK my-network: driver: bridge
volumes: # TẠO Ổ ĐĨA dir-site: # ổ đĩa này lưu dữ liệu ở /mycode/ driver_opts: device: /mycode/ # Hãy đảm bảo có thư mục /mycode/default o: bind

Từ thư mục chứa file docker-compose.yml trên, chạy lệnh sau để để tạo các thành phần mà nó mô tả:

docker-compose up

Kết quả thể hiện với mô hình hóa như sau:

RS

Nhìn vào sơ đồ kết quả ta thấy:

  • Có 4 container đang chạy (mysql-product, c-httpd01, php-product, c-memcached01), chúng được nối vào mạng my-network vậy giữa chúng có thể liên lạc với nhau qua cổng tương ứng (3304, 80, 9000, 11211). Riêng container có public cổng 8080 ánh xạ vào cổng 80 của nó, vậy bên ngoài mạng có thể kết nối tới nó qua cổng 8080
  • Có ổ đĩa dir-site dữ liệu nó lưu tại máy HOST /mycode/, ổ đĩa này cũng nối vào container c-http01 ở thư mục /home/sites. Tương tự nó cũng nối vào php-product
  • Container mysql-product cũng ánh xạ thư mục /mycode/db vào /var/lib/mysql

Nếu cần chỉnh sủa file docker-compose.yml, thì hãy gỡ các thành phần tạo ra bởi lệnh docker-compose up bằng cách gõ:

docker-compose down

Sau khi sửa xong chạy lại docker-compose up

Lưu ý về Container MYSQL

MySQL trên chạy là phiên bản mới 8.x, nên tài khoản root mặc định tạo ra ban đầu dùng cơ chế xác thực mới, rất nhiều ứng dụng chưa sử dụng thư viện kết nối mới này, nên có thể bạn cần chuyển sang xác thực mysql_native_password, ví dụ chuyển tài khoản root sang cơ chế xác thực mysql_native_password:

docker exec -it mysql-product bash          # vào container
apt-get update && apt-get install vim -y    # cài vim
vim /etc/mysql/my.cnf                       # vào chỉnh sửa my.cnf

# vào mysql với password abc123
mysql -pabc123

# chạy các query
ALTER USER 'root'@'%' IDENTIFIED WITH mysql_native_password BY 'abc123';
FLUSH PRIVILEGES;
exit;

# Ra khỏi container và gõ để khởi động lại
docker restart mysql-product

Như vậy đã tạo được một hệ thống, chạy ứng dụng Web (Apache, PHP, MySQL) có dùng Memcached. Từ đây chỉ việc để mã nguồn của ứng dụng bất kỳ vào ổ đĩa dir-site và sử dụng.

Ví dụ cài đặt Joomla

Ta thử cài đặt CMS nguồn mở Joomla vào hệ thống trên.

  • Hãy Tải Joomla về, giải nén để có thư mục mã nguồn của Joomla.
  • Hệ thống trên đang chạy ứng dụng mặc định ở thư mục /home/sites/default (tương ứng /mycode/default trong máy HOST), bạn có thể cấu hình Apache để chạy với nhiều tên miền, nhiều ứng dụng mỗi ứng dụng là một thư mục nào đó do bạn tạo
  • Copy tất cả các file trong thư mục mã nguồn tải về vào thư mục tại máy HOST /mycode/default

Vào địa chỉ http://localhost:8080 để bắt đầu cài đặt.

Nhập thông tin website muốn cài và tài khoản quản trị muốn tạo, rồi bấm vào Tiếp theo

joomla 1

Khai báo kết nối đến MySQL: chú ý để nối đến MySQL tên máy chủ phải điền sao cho nó liên lạc đến container tưng ứng, đây chỉnh là mysql-product:3306, điền tài khoản kết nối MySQL đã tạo (root, pass là abc123 nếu chưa đổi), điền tên CSDL muốn tạo và bấm Tiếp Theo

joomla 2

Bấm vào cài đặt

joomla 3

Cài đặt thành công

joomla 4

Website kết quả

joomla 5

MẪU docker-compose.yml

Đăng ký theo dõi ủng hộ kênh