Deploy laravel project use docker compose

  • November 23, 2024
  • 58

Chúng ta đã tự build một server cho dự án laravel, bằng cách cài đặt các service trực tiếp trên server. Hôm nay chúng ta sẽ làm điều này sử dụng docker compose. Để sử dụng được docker compose thì việc đầu tiên cần làm là cài đặt docker và docker compose trên server. Sau đó cấu hình các dịch vụ sử dụng docker compose

1. Create docker compose

Tạo file docker-compose.yml để khai báo các service cần thiết cho dự án


version: "3.7"

networks:
  backend:

services:
  nginx:
    build:
      context: .
      dockerfile: docker/Dockerfile.nginx
      args:
        PHP_FPM_SERVER: php
        PHP_FPM_PORT: 9000
    ports:
      - ${DOCKER_NGINX_PORT}:80
      - 443:443
    depends_on:
      - app
    links:
      - app
    volumes:
      - .:/var/www/html
      - /etc/ssl:/etc/ssl
      - ./docker/nginx/default.conf:/etc/nginx/conf.d/default.conf
  networks:
    - backend

  app:
    build:
      context: .
      dockerfile: docker/Dockerfile
      args:
        XDEBUG: "true"
    volumes:
      - .:/var/www/html
      - ./docker/php.ini:/usr/local/etc/php/conf.d/php.ini
    links:
      - db
    networks:
      - backend

  db:
    image: mysql:8.1
    restart: unless-stopped
    ports: []
    expose:
      - 3306
    environment:
      MYSQL_DATABASE: ${DB_DATABASE}
      MYSQL_USER: ${DB_USERNAME}
      MYSQL_PASSWORD: ${DB_PASSWORD}
      MYSQL_ROOT_PASSWORD: root
    volumes:
      - ./db_mysql:/var/lib/mysql/
    etworks:
      - backend

Chúng ta sẽ build 3 container: nginx, app và db để chạy ứng dụng laravel. Chú ý các dịch vụ app và db chúng ta không được mở post ra ngoài để bảo mật cho dự án, chỉ public post 80 và 443 của nginx. Nếu mở post ra ngoài sẽ rất dễ bị hack.

2. Create dockerfile

Tạo thư mục docker cùng cấp với file docker-compose.yml để định nghĩa dockerfile cho container nginx và app. Đọc bài viết tạo dockerfile cho cho dự án laravel để lấy dockerfile cho container app. Tạo dockerfile cho container nginx


FROM nginx:1.19.2-alpine

ARG PHP_FPM_SERVER=127.0.0.1
ARG PHP_FPM_PORT=9000
COPY docker/nginx.conf /tmp/nginx.conf
RUN envsubst '$PHP_FPM_SERVER $PHP_FPM_PORT' < /tmp/nginx.conf > /etc/nginx/conf.d/default.conf

EXPOSE 80 443
CMD ["nginx", "-g", "daemon off;"]

Tạo file docker/nginx.conf để cấu hình nginx local không sử dụng ssl


server {
    listen 80;
    server_name _;
    root /var/www/html/public;

    client_max_body_size 650M;

    error_log  /var/log/nginx/error.log;
    access_log /var/log/nginx/access.log;

    location / {
        try_files $uri $uri/ /index.php$is_args$args;

        if ($request_method = OPTIONS) {
            return 204;
        }

        add_header Access-Control-Allow-Origin *;
        add_header Access-Control-Max-Age 3600;
        add_header Access-Control-Expose-Headers Content-Length;
        add_header Access-Control-Allow-Headers *;
        add_header Access-Control-Allow-Methods *;

        autoindex off;
        index  index.php;
    }
    location ~ \.php$ {
        set $path_info $fastcgi_path_info;
        fastcgi_index index.php;
        fastcgi_split_path_info ^(.+\.php)(/.*)$;
        include /etc/nginx/fastcgi_params;
        fastcgi_pass $PHP_FPM_SERVER:$PHP_FPM_PORT;
        fastcgi_param SCRIPT_FILENAME $request_filename;
        fastcgi_param PHP_VALUE "upload_max_filesize=650M \n post_max_size=650M";
        fastcgi_read_timeout 300s;
    }
}

Tạo file docker/nginx.conf để cấu hình nginx server sử dụng ssl


# HTTP -> HTTPS Redirect
server {
    listen 80;
    server_name demo.com;

    # Redirect all HTTP traffic to HTTPS
    return 301 https://$host$request_uri;
}

# HTTPS Configuration
server {
    listen 443 ssl;
    server_name demo.com;

    root /var/www/html/public;

    # SSL Certificate
    ssl_certificate /etc/ssl/certificate.crt;
    ssl_certificate_key /etc/ssl/private.key;

    # SSL Options
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers HIGH:!aNULL:!MD5;
    ssl_prefer_server_ciphers on;

    client_max_body_size 650M;

    error_log  /var/log/nginx/error.log;
    access_log /var/log/nginx/access.log;

    location / {
        try_files $uri $uri/ /index.php$is_args$args;

        if ($request_method = OPTIONS) {
            return 204;
        }

        add_header Access-Control-Allow-Origin *;
        add_header Access-Control-Max-Age 3600;
        add_header Access-Control-Expose-Headers Content-Length;
        add_header Access-Control-Allow-Headers *;
        add_header Access-Control-Allow-Methods *;

        autoindex off;
        index index.php;
    }

    location ~ \.php$ {
        set $path_info $fastcgi_path_info;
        fastcgi_index index.php;
        fastcgi_split_path_info ^(.+\.php)(/.*)$;
        include /etc/nginx/fastcgi_params;
        fastcgi_pass php:9000;
        fastcgi_param SCRIPT_FILENAME $request_filename;
        fastcgi_param PHP_VALUE "upload_max_filesize=650M \n post_max_size=650M";
        fastcgi_read_timeout 300s;
    }
}

Để đăng kí ssl cho server chúng ta sẽ sử dụng let's encrypt certbot. Chúng ta sẽ đăng kí key ssl ở server trong thư mục /etc/ssl sau đó mount key vào container nginx để web có thể chạy được ssl.

Thêm file docker/php.ini cấu hình cho php


[PHP]
post_max_size = 650M
upload_max_filesize = 650M
variables_order = EGPCS
max_multipart_body_parts = 5000
max_input_vars = 5000

3. Run docker command

Để chạy các container trên server chúng ta chạy command sau


// Cd to workspace
// Build docker image
docker-composer build
// Run container
docker-compose up -d
// Run container with special file
docker-compose -f docker-compose.dev.yml up -d
// Stop special service
docker-compose stop [service_name]
// Start special service
docker-compose start [service_name]
// Check log
docker-compose logs -f [service_name]
// Access to container
docker-compose exec app bash
docker-compose -f docker-compose.dev.yml exec app bash

4. Run laravel command

Làm sao để update thư viện, migration, seed khi code được update


// Khi code có update thư viện
docker-compose exec [service_name] composer install
// Migrate db
docker-compose exec [service_name] php artisan migrate

Thêm script deploy khi sử dụng jenkin khi deploy code to server


#!/bin/bash

# Execute commands remotely via SSH without TTY allocation
ssh demo-app << 'SSH_EOF'

# Commands to run on the remote server
cd ~/var/www/html/demo
git pull
docker-compose exec app sh -c 'composer install && php artisan migrate && php artisan db:seed && php artisan optimize:clear && php artisan cache:clear'
SSH_EOF

Tổng kết

Như vậy là chúng ta đã thiết lập xong docker để chạy dự án laravel. Thiết lập thông qua docker sẽ giúp tiết kiệm thời gian hơn cài trực tiếp trên server. Nhưng cần chú ý đến việc mở post đúng cách. Rất nhiều người đã bị hack drop database khi mở post 3306 ra ngoài. Thanks for reading...