Tìm hiểu về Docker - Phần 7 - Làm việc với Docker Compose

Mở đầu

Hello xin chào mọi người. Ở bài viết trước, chúng ta đã cùng nhau tìm hiểu về Docker Compose và hiểu được cấu trúc cơ bản của nó thông qua 1 ví dụ nho nhỏ rồi. Vậy thì hôm nay, chúng ta thử sử dụng docker-compose để build một môi trường cho dự án Laravel để hiểu cách sử dụng cơ bản chứ nhỉ?

Không dài dòng nữa, cùng chiến thôi nào !

Laravel với docker-compose

1. Lưu ý

  • Nhất định máy của bạn đã và đang được cài Docker rồi nhé. Và hãy run nó lên ngay đi nào.
  • Theo như documention của Laravel thì để có thể chạy được Laravel mới nhất (8.x) thì yêu cầu hệ điều hành của bạn cần phải cài:
    • PHP >= 7.3
    • BCMath PHP Extension
    • Ctype PHP Extension
    • Fileinfo PHP Extension
    • JSON PHP Extension
    • Mbstring PHP Extension
    • OpenSSL PHP Extension
    • PDO PHP Extension
    • Tokenizer PHP Extension
    • XML PHP Extension
  • Webserver thì có thể sử dụng Apache hoặc Nginx. Tuy nhiên theo mình thì bạn nên cài NginxPHP-FPM để có hiệu năng tốt hơn vì vậy ở bài viết này mình sẽ sử dụng Nginx thay vì Apache. Ngoài ra chúng ta cũng sẽ dùng thêm một số container khác như MySQL,…
  • Bài này sẽ không cài đặt tất cả các thứ ở trên vào môi trường máy của bạn mà chúng sẽ được cài vào các container docker.

2. Cài đặt.

Nếu bạn mới bắt đầu tìm hiểu về laravel thì có thể clone source code laravel từ https://github.com/laravel/laravel hoặc bạn có thể chọn phiên bản bạn cần download về và giải nén tại https://github.com/laravel/laravel/releases

Còn nếu bạn đã dùng laravel rồi và đã cài đặt composer thì đây:

composer create-project --prefer-dist laravel/laravel laravel

Tiếp tục nhé, giả sử bạn đã có source code một project laravel trên máy hoặc kéo từ github của bạn về.

PHP-FPM

Ngoài việc cài các PHP extensions, chúng ta sẽ cài thêm một số công cụ vì đây là container thường được sử dụng để tương tác với Laravel thông qua lệnh php artisan như git, vim, cron để chạy Laravel cron hay composer (cần thêm unzip)…

Tạo một file php.Dockerfile:

FROM php:7.3-fpm

RUN apt-get update && apt-get install -y \
    libmcrypt-dev \
    openssl \
    curl \
    git vim unzip cron \
    --no-install-recommends \
    && rm -r /var/lib/apt/lists/*

RUN docker-php-ext-install -j$(nproc) \
    bcmath \
    pdo_mysql \
    tokenizer

# Install PHP Xdebug 2.9.8
RUN pecl install -o xdebug-2.9.8

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

RUN curl -sL https://deb.nodesource.com/setup_14.x | bash - \
    && apt-get install -y nodejs \
    && npm install -g n \
    && n stable

RUN cp "$PHP_INI_DIR/php.ini-development" "$PHP_INI_DIR/php.ini"

CMD ["php-fpm"]

Vậy là bạn đã có docker-compose service đầu tiên:

php:
    container_name: php
    build:
      context: ./
      dockerfile: php.Dockerfile
    volumes:
      - "./:/var/www/html"

Nginx

Tiếp theo là container cho web server Nginx, có nhiệm vụ giao tiếp với PHP-FPM và trả về response cho client. Với service này, để tận dụng khả năng dùng lại các image có sẵn và giảm bớt việc phải build image, nên chúng ta không cần sử dụng custom Dockerfile, ở đây chỉ cần sử dụng image nginx và thực hiện mount file config:

nginx:
    image: nginx:latest
    container_name: nginx
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - "./default.conf:/etc/nginx/conf.d/default.conf"
      - "./:/var/www/html"

Tạo 1 file default.conf sẽ chứa configurate cho phép nginx có thể chạy được các file php:

server {
    listen 80;
    index index.php index.html;
    server_name _;
    error_log  /var/log/nginx/error.log;
    access_log /var/log/nginx/access.log;
    root /var/www/html/public;

    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    location ~ \.php$ {
        try_files $uri =404;
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_pass php:9000;
        fastcgi_index index.php;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param PATH_INFO $fastcgi_path_info;
    }
}

MySQL

Tương tự, chúng ta cũng có thể dùng image mysql trực tiếp và tạo user, db qua init SQL file mà không cần custom image:

mysql:
    image: mysql:5.7
    container_name: mysql
    command: --default-authentication-plugin=mysql_native_password
    restart: 'on-failure'
    cap_add:
      - SYS_NICE
    environment:
      MYSQL_DATABASE: ${DB_DATABASE} # Được lấy từ biến môi trường .env
      MYSQL_USER: ${DB_USERNAME} # Được lấy từ biến môi trường .env
      MYSQL_PASSWORD: ${DB_PASSWORD} # Được lấy từ biến môi trường .env
      MYSQL_ROOT_PASSWORD: "root"
    ports:
      - "3306:3306"

Sau khi hoàn tất các phần trên, chúng ta có file docker-compose.yml hoàn thiện như sau:

version: '3.9'
services:
  php:
    container_name: php
    build:
      context: ./
      dockerfile: php.Dockerfile
    volumes:
      - "./:/var/www/html"
  nginx:
    image: nginx:latest
    container_name: nginx
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - "./default.conf:/etc/nginx/conf.d/default.conf"
      - "./:/var/www/html"
  mysql:
    image: mysql:5.7
    container_name: mysql
    command: --default-authentication-plugin=mysql_native_password
    restart: 'on-failure'
    cap_add:
      - SYS_NICE
    environment:
      MYSQL_DATABASE: ${DB_DATABASE}
      MYSQL_USER: ${DB_USERNAME}
      MYSQL_PASSWORD: ${DB_PASSWORD}
      MYSQL_ROOT_PASSWORD: "root"
    ports:
      - "3306:3306"

3. Chạy dự án với docker-compose

Sau khi làm xong các bước trên, giờ bạn chỉ cần khởi động chương trình thôi:

$ docker-compose up -d

Khi bạn chạy lệnh trên, docker sẽ tự động build image từ Dockerfile hoặc sẽ pull images đã được khai báo trong file docker-compose.yml.

Lần đầu tiên chạy sẽ mất khoảng vài phút để xây dựng các container, nhưng từ lần thứ 2 trở đi là sẽ chạy luôn.
Chú ý: Khi bạn sửa đổi một file dockerfile (php.dockerfile) nào thì bạn phải chạy câu lệnh sau để build lại hệ thống: docker-compose build

Tiếp đến là chạy composer:

$ docker-compose run php composer install

Thực hiện lệnh tạo file .env bằng cách copy từ file mẫu .env.example:

$ docker-compose run php cp .env.example .env

Tạo key để sử dụng laravel:

$ docker-compose run php php artisan key:generate

Các câu lệnh docker-compose run php [command] là bạn đang đứng tại môi trường máy của bạn gửi yêu cầu vào trong các container thông qua docker-composer để chạy các command liên quan cho dự án. Hoặc bạn có thể ssh vào các container sau đó thực hiện các câu lệnh cho thoái mái nhé.

Sau đó, cấp quyền cho các thư mục cần thiết:

$ chmod 777 -R bootstrap storage

Lưu ý: Khi các bạn sử dụng docker để triển khai trên môi trường production, các bạn nên set quyền phù hợp để đảm bảo bảo mật cho dự án. Mình sử dụng quyền 777 khi đang triển khai trên môi trường local. Để tìm hiểu về các quyền các bạn có thể tham khảo tại đây

Để kiểm tra các images vừa xây dựng và các container đang chạy:

$ docker images
$ docker ps

Nếu dự án Laravel của bạn đã và đang được triển khai thì để có thể migrate database thì bạn cần phải sửa các biến môi trường trong file .env thành (Đây là các biến môi trường được đặt theo ví dụ):

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

Sau khi các images và container đã sẵn sàng và được khởi chạy, hãy truy cập địa chỉ http://127.0.0.1 trên browser để tận hưởng thành quá nhé.

Một ngày học tập và làm việc đầy mệt mỏi đúng không? Để tắt các container thì các bạn chỉ cần sử dụng lệnh:

$ docker-compose down

Như vậy docker-compose sẽ tự động dừng lại tất cả các container services mà bạn đã khai báo bên trong file docker-compose.yml.

Tổng kết

Vậy là chúng ta vừa thử tích hợp docker vào dự án Laravel một cách cơ bản nhất. Bạn cảm thấy thế nào?

Hãy để lại bình luận và góp ý cho mình để chúng ta cùng nhau phát triển nhé.

Cảm ơn bạn đã dành thời gian cho bài viết của mình. Hẹn gặp vào bài viết tiếp theo của series Tìm hiểu về Docker nhé !