Cài đặt Laravel trên Docker

 Cài đặt laravel trên docker

1. Vì sao nên sử dụng Docker

Vào một ngày đẹp trời, trăng thanh gió mát, bạn được sếp phân bổ vào một dự án mới. Với khí thế ngút trời bạn vào file README.md đọc một hồi thấy để chạy dự án này sao phải cài lắm thứ thế. Nào là PHPNginxMySQLRedisElasticSearch,... Mỗi thứ lại phải yêu cầu version x.x, cấu hình y.y và hàng tá các thứ khác. Điều này khiến bạn bị ngợp, và tự hỏi là cài cái này bao giờ mới xong ta.

Sếp ơi! Em cần một buổi sáng để setup ạ

Cài chưa xong đã thấy lỗi tùm lum rồi, cái này xung đột với cái kia, chưa kể có thể còn làm ảnh hưởng tới dự án cũ có khi còn ảnh hưởng tới cả chương trình đã cài đặt trong máy ấy chứ. Thôi cài lại luôn hệ điều hành cho máy luôn đi cho lành

Sếp ơi! Em cần thêm một buổi nữa mới xong ạ

Thôi xong mất thời gian vào mấy việc phụ mà chưa tập trung được vào công việc chính. Sad..hic...hic Điều này khiến bạn nghĩ tới một giải pháp "Perfect choice" nào đấy kiểu như One click install vậy. Và Docker đã đượct tạo ra nhằm mục đích đấy

2. Các công cụ cần thiết

  1. Docker (Nếu chưa cài bạn có thể cài đặt theo hướng dẫn tại https://docs.docker.com/engine/install/)
  2. Docker Compose (Hướng dẫn cài đặt tại https://docs.docker.com/compose/install/)
  3. Kết nối internet

3. Tích hợp Docker vào dự án

Đầu tiên để có thể cài đặt được Laravel thì tất nhiên bạn có source code của laravel đã nhỉ. Có 2 cách để có thể có source code của laravel

  1. Nếu bạn đã cài đặt composer
    composer create-project --prefer-dist laravel/laravel laravel
    
  2. Nếu bạn chưa cài đặt composer 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

System Requirment

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 Nginx và PHP-FPM để có hiệu năng tốt hơn vì vậy ở bài viết này tớ 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ư MySQLRedis,...

Ok chúng ta bắt tay vào việc thôi Về cơ bản chúng ta sẽ xây dựng các docker container như sau:

Implement Docker Laravel

Sử dụng docker-compose, mỗi container được mô tả bằng một service:

version: '3.5'

services:
  php:
    #...
  nginx:
    #...
  mysql:
    #...
  phpmyadmin:
    #...
  redis:
    #...

PHP-FPM

Vì mình tìm trên docker hub không thấy có image nào phù hợp nên chúng ta sẽ tự tạo một image bằng php.Dockerfile.

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ư gitvimcron để chạy Laravel cron hay composer (cần thêm unzip)...

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"

ADD etc/docker-php.ini $PHP_INI_DIR/conf.d/
ADD etc/docker-php-xdebug.ini $PHP_INI_DIR/conf.d/zz-xdebug-settings.ini

ADD php.docker-entroypoint.sh /usr/local/bin/

RUN ["chmod", "+x", "/usr/local/bin/php.docker-entroypoint.sh"]

ENTRYPOINT [ "/usr/local/bin/php.docker-entroypoint.sh" ]

CMD ["php-fpm"]

Sau khi cài xong các package trong hệ thống, chúng ta xóa cache của apt-get để giảm kích thước của image.

Sau đó là tạo file php.ini mặc định từ file example php.ini-development và add một số setting khác bằng file docker-php.ini:

Mặc định, container chạy ở cổng 9000, do đó các container khác, cụ thể là nginx có thể kết nối vào địa chỉ: php:9000

Ta có docker-compose service đầu tiên:

php:
    container_name: php
    build:
      context: docker/docker
      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:
      - "./docker/config/nginx/default.conf:/etc/nginx/conf.d/default.conf"
      - "./docker/logs/nginx:/var/log/nginx/"
      - "./:/var/www/html"

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_ALLOW_EMPTY_PASSWORD: "false"
      MYSQL_ROOT_PASSWORD: "root"
      MYSQL_DATABASE: "laravel"
    volumes:
      - "./docker/mysql:/var/lib/mysql"
      - "./docker/config/mysql/custom.cnf:/etc/mysql/conf.d/mysql.cnf"
      - "./docker/logs/mysql/query.log:/var/log/query.log"
    ports:
      - "3306:3306"

Để có thể tương tác với MySQL dễ dàng hơn ta cần sử dụng thêm bộ công cụ PHPMyAdmin hoặc bạn có thể kết nối với host machine như (MySQL Workbench,...) với port 3306 nếu bạn bị trùng port hãy đổi trong file docker-compose.yml

phpmyadmin:
    image: phpmyadmin/phpmyadmin
    container_name: phpmyadmin
    restart: always
    ports:
      - '8080:80'
    environment:
      PMA_HOST: mysql

Bây giờ bạn đã có thể truy cập vào phpmyadmin với đường dẫn http://localhost:8080

user: root
pass: root

Lệnh cài đặt ban đầu:

docker-compose up -d
docker-compose run php composer install
docker-compose run php cp .env.example .env
docker-compose run php php artisan key:generate

Lưu ý

Nếu gặp lỗi

storage/logs/laravel.log" could not be opened: failed to open stream: permission denied

Hãy chạy thêm lệnh sau để cấp quyền cho thư mục:

chmod 777 -R bootstrap storage

Để có thể migrate database ta cần phải sửa trong file .env thành

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

Redis

Docker config cho redis cũng khá đơn giản:

redis:
    image: redis
    container_name: redis
    hostname: redis
    restart: 'on-failure'

Tiếp theo thêm domain vào /etc/hosts:

127.0.0.1       laravel.local

Vậy là xong. Bây giờ vào đường đẫn laravel.local để xem kết quả.

Trên đây là công việc mình config docker lúc ban đầu, bạn nào muốn sử dụng luôn thì xem hướng dẫn ở Github nhé: https://github.com/tieugum/laravel-docker