---
title: "Cách cài đặt và thiết lập Laravel với Docker Compose trên Ubuntu 20.04"
description: "Cách cài đặt và thiết lập Laravel với Docker Compose trên Ubuntu 20.04"
url: https://cloudfly.vn/techblog/cach-cai-dat-va-thiet-lap-laravel-voi-docker-compose-tren-ubuntu-2004
image: https://media.cloudfly.vn/posts/techblog_093I9Rt.png
---

# Cách cài đặt và thiết lập Laravel với Docker Compose trên Ubuntu 20.04

![description image](https://media.cloudfly.vn/posts/Cach-cai-dat-va-thiet-lap-Laravel-voi-Docker-Compose-tren-Ubuntu-20-04.jpg)
## Giới thiệu
Nơi chứa đựng một ứng dụng và các thành phần của nó để có thể vận hành trong môi trường nhẹ được gọi là vùng chứa. Những môi trường như vậy được tách biệt và chỉ sử dụng một lần. Và nó còn có thể được tận dụng để phát triển, thử nghiệm và triển khai các ứng dụng khác. 

Trong hướng dẫn này, chúng tôi sẽ sử dụng Docker Compose để chứa và phát triển một ứng dụng Laravel. Khi hoàn tất, bạn sẽ có một ứng dụng Laravel demo đang chạy trên 3 vùng chứa dịch vụ riêng biệt:
* Một `app` dịch vụ chạy PHP7.4-FPM;
* Một dịch vụ `db` chạy MySQL 5.7;
* Một dịch vụ `nginx` sử dụng dịch vụ `app` để phân tích cú pháp mã PHP trước khi cung cấp ứng dụng Laravel cho người dùng cuối cùng.

Để cho phép quy trình phát triển được tổ chức hợp lý và tạo điều kiện thu hồi các lỗi ứng dụng, chúng tôi sẽ giữ cho các tệp ứng dụng được đồng bộ hóa bằng cách sử dụng khối lượng dữ liệu được chia sẻ trước đó. Chúng ta cũng sẽ xem xét cách thức sử dụng các lệnh thực thi của `docker-comp` để chạy Composer và Artisan trên vùng chứa `app`.
## Điều kiện 
* Truy cập vào máy cục bộ hoặc máy chủ hệ điều hành Ubuntu 20.04 với non-root user có đặc quyền sudo. Nếu bạn đang sử dụng máy chủ từ xa, bạn nên cài đặt tường lửa. 
* Cài đặt sẵn Docker trên máy chủ của bạn.
* Cài đặt sẵn Docker Compose trên máy chủ của bạn.
## Bước 1 : Lấy ứng dụng Demo
Để bắt đầu, chúng tôi sẽ tìm nạp ứng dụng Laravel demo từ kho Github của nó. Chúng tôi quan tâm đến nhánh hướng dẫn `tutorial-01`, chứa ứng dụng Laravel cơ bản.

Để lấy mã ứng dụng tương thích với hướng dẫn này, hãy tải xuống hướng dẫn phát hành `tutorial-1.0.1` vào thư mục chính của bạn với:
```custom_prefix($)
cd ~
curl -L https://github.com/do-community/travellist-laravel-demo/archive/tutorial-1.0.1.zip -o travellist.zip
```

Chúng tôi sẽ cần lệnh giải nén `unzip`để giải nén mã ứng dụng. Trong trường hợp bạn chưa cài đặt gói này trước đây, hãy làm như vậy ngay bây giờ với:
```custom_prefix($)
sudo apt update
sudo apt install unzip
```

Bây giờ, hãy giải nén nội dung của ứng dụng và đổi tên thư mục đã giải nén để truy cập dễ dàng hơn:
```custom_prefix($)
unzip travellist.zip
mv travellist-laravel-demo-tutorial-1.0.1 travellist-demo
```

Điều hướng đến danh sách `travellist-demo`:
```custom_prefix($)
cd travellist-demo
```


## Bước 2: Thiết lập tệp `.env` của ứng dụng
Các tệp cấu hình Laravel được đặt trong một thư mục được gọi là `config`, bên trong thư mục gốc của ứng dụng. Ngoài ra, tệp `.env` được sử dụng để thiết lập cấu hình phụ thuộc vào môi trường, chẳng hạn như thông tin xác thực và bất kỳ thông tin nào có thể khác nhau giữa các lần triển khai. Tệp này không được bao gồm trong kiểm soát sửa đổi.

<$>[warning]
**Cảnh báo:** Tệp cấu hình môi trường chứa thông tin nhạy cảm về máy chủ của bạn, bao gồm thông tin xác thực cơ sở dữ liệu và khóa bảo mật. Vì lý do đó, bạn không bao giờ nên chia sẻ công khai tệp này.
<$>

Các giá trị có trong tệp `.env` sẽ được ưu tiên hơn các giá trị được đặt trong tệp cấu hình thông thường nằm tại thư mục  `config`. Mỗi cài đặt trên môi trường mới yêu cầu tệp môi trường được điều chỉnh để xác định những thứ như cài đặt kết nối cơ sở dữ liệu, tùy chọn gỡ lỗi, URL ứng dụng, trong số các mục khác có thể khác nhau tùy thuộc vào môi trường ứng dụng đang chạy.

Bây giờ chúng tôi sẽ tạo một tệp `.env` mới để tùy chỉnh các tùy chọn cấu hình cho môi trường phát triển mà chúng tôi đang thiết lập. Laravel đi kèm với tệp `example.env` mà chúng ta có thể sao chép để tạo tệp của riêng mình:
```custom_prefix($)
cp .env.example .env
```
Mở tệp này bằng `nano` hoặc bất kỳ trình soạn thảo văn bản mà bạn chọn:
```custom_prefix($)
nano .env
```

Tệp `.env` hiện tại từ ứng dụng demo `travellist` chứa cài đặt để sử dụng cơ sở dữ liệu MySQL cục bộ, với `127.0.0.1` làm máy chủ cơ sở dữ liệu. Chúng ta cần cập nhật biến `DB_HOST` để nó trỏ đến dịch vụ cơ sở dữ liệu mà chúng ta sẽ tạo trong môi trường Docker của mình. Trong hướng dẫn này, chúng tôi sẽ gọi dịch vụ cơ sở dữ liệu của chúng tôi là `db`. Hãy tiếp tục và thay thế giá trị được liệt kê của `DB_HOST` bằng tên dịch vụ cơ sở dữ liệu:
```nginx
[label .env]
APP_NAME=Travellist
APP_ENV=dev
APP_KEY=
APP_DEBUG=true
APP_URL=http://localhost:8000

LOG_CHANNEL=stack

DB_CONNECTION=mysql
DB_HOST=db
DB_PORT=3306
DB_DATABASE=travellist
DB_USERNAME=travellist_user
DB_PASSWORD=password
...
```
Vui lòng thay đổi tên cơ sở dữ liệu, tên người dùng và mật khẩu nếu bạn muốn. Các biến này sẽ được tận dụng trong bước sau, nơi chúng tôi sẽ thiết lập tệp `docker-compost.yml` để định cấu hình các dịch vụ của mình.

Lưu tệp khi bạn chỉnh sửa xong. Nếu bạn đã sử dụng `nano`, bạn có thể làm điều đó bằng cách nhấn `Ctrl + x`, sau đó nhấn `Y` và `Enter` để xác nhận.

## Bước 3: Thiết lập Dockerfile của ứng dụng
Mặc dù cả hai dịch vụ MySQL và Nginx của chúng tôi đều sẽ dựa trên hình ảnh mặc định thu được từ Docker Hub, chúng tôi vẫn cần xây dựng hình ảnh tùy chỉnh cho vùng chứa ứng dụng. Chúng tôi sẽ tạo một Dockerfile mới cho việc đó.

Hình ảnh danh sách du lịch của chúng tôi sẽ dựa trên hình ảnh PHP chính thức `php: 7.4-fpm` từ Docker Hub. Ngoài môi trường PHP-FPM cơ bản đó, chúng tôi sẽ cài đặt một vài mô-đun PHP bổ sung và công cụ quản lý phụ thuộc của trình soạn thảo.

Chúng tôi cũng sẽ tạo một người dùng hệ thống mới; điều này là cần thiết để thực hiện các lệnh của `artisan` và `composer` trong khi phát triển ứng dụng. Cài đặt `uid` đảm bảo rằng người dùng bên trong vùng chứa có cùng `uid` với người dùng hệ thống của bạn trên máy chủ, nơi bạn đang chạy Docker. Bằng cách này, bất kỳ tệp nào được tạo bởi các lệnh này đều được sao chép trong máy chủ lưu trữ với các quyền chính xác. Điều này cũng có nghĩa là bạn sẽ có thể sử dụng trình chỉnh sửa mã mà bạn chọn trong máy chủ để phát triển ứng dụng đang chạy bên trong vùng chứa.

Tạo một Dockerfile mới với:
```custom_prefix($)
nano Dockerfile
```
Sao chép các nội dung sau vào Dockerfile của bạn:
```nginx
[label Dockerfile]
FROM php:7.4-fpm

# Arguments defined in docker-compose.yml
ARG user
ARG uid

# Install system dependencies
RUN apt-get update && apt-get install -y \
    git \
    curl \
    libpng-dev \
    libonig-dev \
    libxml2-dev \
    zip \
    unzip

# Clear cache
RUN apt-get clean && rm -rf /var/lib/apt/lists/*

# Install PHP extensions
RUN docker-php-ext-install pdo_mysql mbstring exif pcntl bcmath gd

# Get latest Composer
COPY --from=composer:latest /usr/bin/composer /usr/bin/composer

# Create system user to run Composer and Artisan Commands
RUN useradd -G www-data,root -u $uid -d /home/$user $user
RUN mkdir -p /home/$user/.composer && \
    chown -R $user:$user /home/$user

# Set working directory
WORKDIR /var/www

USER $user
```
Đừng quên lưu tệp khi bạn hoàn tất xong nhé.

Dockerfile của chúng tôi bắt đầu bằng cách xác định hình ảnh cơ sở mà chúng tôi đang sử dụng: `php: 7.4-fpm`.

Sau khi cài đặt các gói hệ thống và phần mở rộng PHP, chúng tôi cài đặt Composer bằng cách sao chép `composer` thực thi của trình tổng hợp từ hình ảnh chính thức mới nhất của nó sang hình ảnh ứng dụng của riêng chúng tôi.

Một người dùng hệ thống mới sau đó được tạo và thiết lập bằng cách sử dụng các đối số `user` và `uid` đã được khai báo ở đầu Dockerfile. Các giá trị này sẽ được Docker Compose đưa vào tại thời điểm triển khai.

Cuối cùng, chúng tôi đặt `dir` làm việc mặc định là `/ var / www` và thay đổi thành người dùng mới được tạo. Điều này sẽ đảm bảo rằng bạn đang kết nối với tư cách là người dùng thông thường và bạn đang ở đúng thư mục khi chạy các lệnh của `composer` và `artisan` trên vùng chứa ứng dụng.

## Bước 4: Thiết lập cấu hình Nginx và tệp kết xuất cơ sở dữ liệu

Khi tạo môi trường phát triển với Docker Compose, thông thường cần phải chia sẻ các tệp cấu hình hoặc khởi tạo với các vùng chứa dịch vụ, để thiết lập hoặc khởi động các dịch vụ đó. Phương pháp này tạo điều kiện thuận lợi cho việc thực hiện các thay đổi đối với tệp cấu hình để điều chỉnh môi trường trong khi bạn đang phát triển ứng dụng.

Bây giờ chúng tôi sẽ thiết lập một thư mục chứa các tệp sẽ được sử dụng để định cấu hình và khởi chạy các vùng chứa dịch vụ của chúng tôi.

Để thiết lập Nginx, chúng tôi sẽ chia sẻ một tệp `travellist.conf` sẽ định cấu hình cách ứng dụng được phân phối. Tạo thư mục `docker-compos / nginx` với:
```custom_prefix($)
mkdir -p docker-compose/nginx
```

Mở một tệp mới có tên `travellist.conf` trong thư mục đó:
```custom_prefix($)
nano docker-compose/nginx/travellist.conf
```

Sao chép cấu hình Nginx sau vào tệp đó:
```nginx
[label docker-compose/nginx/travellist.conf]
server {
    listen 80;
    index index.php index.html;
    error_log  /var/log/nginx/error.log;
    access_log /var/log/nginx/access.log;
    root /var/www/public;
    location ~ \.php$ {
        try_files $uri =404;
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_pass app:9000;
        fastcgi_index index.php;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param PATH_INFO $fastcgi_path_info;
    }
    location / {
        try_files $uri $uri/ /index.php?$query_string;
        gzip_static on;
    }
}
```
Tệp này sẽ cấu hình Nginx để lắng nghe trên cổng `80` và sử dụng` index.php` làm trang chỉ mục mặc định. Nó sẽ đặt gốc tài liệu thành `/ var / www / public`, sau đó định cấu hình Nginx để sử dụng dịch vụ ứng dụng trên cổng `9000 `để xử lý các tệp `* .php`.
Lưu và đóng tệp khi bạn đã chỉnh sửa xong.

Để thiết lập cơ sở dữ liệu MySQL, chúng tôi sẽ chia sẻ kết xuất cơ sở dữ liệu được nhập khi vùng chứa được khởi tạo. Đây là một tính năng được cung cấp bởi MySQL 5.7  image mà chúng tôi sẽ sử dụng ngay trên vùng chứa đó.

Tạo một thư mục mới cho các tệp khởi tạo MySQL của bạn bên trong thư mục `docker-compose`:
```custom_prefix($)
mkdir docker-compose/mysql
```

Mở một file `.sql` mới:
```custom_prefix($)
nano docker-compose/mysql/init_db.sql
```

Kết xuất MySQL sau đây dựa trên cơ sở dữ liệu mà chúng tôi đã thiết lập từ trước. Nó sẽ tạo một bảng mới có tên các địa điểm. Sau đó, nó sẽ điền vào bảng một tập hợp các vị trí mẫu.

Thêm mã sau vào tệp:
```nginx
[label docker-compose/mysql/db_init.sql]
DROP TABLE IF EXISTS `places`;

CREATE TABLE `places` (
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
  `visited` tinyint(1) NOT NULL DEFAULT '0',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=12 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

INSERT INTO `places` (name, visited) VALUES ('Berlin',0),('Budapest',0),('Cincinnati',1),('Denver',0),('Helsinki',0),('Lisbon',0),('Moscow',1),('Nairobi',0),('Oslo',1),('Rio',0),('Tokyo',0);
```
Bảng `place` chứa ba trường là `id`, `name`, và `visited`. `Visited` là một biểu tượng được sử dụng để xác định các địa điểm vẫn phải đến. Hãy thay đổi địa điểm mẫu hoặc bao gồm những địa điểm mới. Lưu và đóng tệp khi bạn hoàn tất.

## Bước 5 :Tạo môi trường nhiều vùng chứa với Docker Compose
Docker Compose cho phép bạn tạo môi trường nhiều vùng chứa cho các ứng dụng chạy trên Docker. Nó sử dụng các định nghĩa dịch vụ để xây dựng các môi trường hoàn toàn có thể tùy chỉnh với nhiều vùng chứa có thể chia sẻ mạng và khối lượng dữ liệu. Điều này cho phép tích hợp liền mạch giữa các thành phần ứng dụng.

Để thiết lập các định nghĩa dịch vụ, chúng tôi sẽ tạo một tệp mới có tên là `docker-compos.yml`. Thông thường, tệp này nằm ở thư mục gốc của thư mục ứng dụng và nó xác định môi trường được chứa trong vùng chứa của bạn, bao gồm các hình ảnh cơ sở mà bạn sẽ sử dụng để tạo vùng chứa của mình và cách các dịch vụ của bạn sẽ tương tác.

Chúng tôi sẽ xác định ba dịch vụ khác nhau trong tệp `docker-compos.yml` của mình: `app`, `db` và `nginx`.

`app` dịch vụ sẽ xây dựng một hình ảnh được gọi là `travellist`, dựa trên Dockerfile mà chúng tôi đã tạo trước đó. Vùng chứa được xác định bởi dịch vụ này sẽ chạy một máy chủ `php-fpm` để phân tích cú pháp PHP và gửi kết quả trở lại dịch vụ `nginx`, dịch vụ này sẽ chạy trên một vùng chứa riêng biệt. Dịch vụ `mysql` xác định một vùng chứa chạy một máy chủ MySQL 5.7. Các dịch vụ của chúng tôi sẽ chia sẻ một mạng lưới cầu nối có tên là `travellist`.

Các tệp ứng dụng sẽ được đồng bộ hóa trên cả `app`và dịch vụ `nginx` thông qua gắn kết ràng buộc. Gắn kết hữu ích trong môi trường phát triển vì chúng cho phép đồng bộ hai chiều hiệu quả giữa máy chủ và vùng chứa.

Tạo tệp `docker-compost.yml` mới ở thư mục gốc của thư mục ứng dụng:
```custom_prefix($)
nano docker-compose.yml
```
Tệp `docker-compo.yml` điển hình bắt đầu với định nghĩa phiên bản, theo sau là nút `server`, theo đó tất cả các dịch vụ được định nghĩa. Mạng chia sẻ thường được xác định ở cuối tệp đó.

Để bắt đầu, hãy sao chép mã bảng soạn sẵn này vào tệp `docker-compost.yml` của bạn:
```nginx
[label /etc/nginx/sites-available/default]
version: "3.7"
services:


networks:
  <^>travellist<^>:
    driver: bridge
```
Bây giờ, chúng ta sẽ edit nút `services` bên trong tệp `ocker-compose.yml`: 
### `App` dịch vụ
`App` dịch vụ sẽ thiết lập một vùng chứa có tên là `travellist-app`. Nó xây dựng một hình ảnh Docker mới dựa trên một Dockerfile nằm trong cùng đường dẫn với tệp `docker-compos.yml`. Hình ảnh mới sẽ được lưu cục bộ trong danh sách `travellist` nêu trên.

Mặc dù thư mục gốc chứa tài liệu đang được phân phát dưới dạng các tệp ứng dụng nằm trong vùng chứa `nginx`, chúng tôi cũng cần các tệp ứng dụng ở đâu đó bên trong vùng chứa `app`, vì vậy chúng tôi có thể thực thi các tác vụ dòng lệnh bằng công cụ Laravel Artisan.

Sao chép định nghĩa `services` sau bên dưới nút dịch vụ của bạn, bên trong tệp `docker-compos.yml`:
```nginx
[label docker-compose.yml]
  app:
    build:
      args:
        user: <^>sammy<^>
        uid: <^>1000<^>
      context: ./
      dockerfile: Dockerfile
    image: <^>travellist<^>
    container_name: <^>travellist-app<^>
    restart: unless-stopped
    working_dir: /var/www/
    volumes:
      -<^> ./:/var/www<^>
    networks:
      - <^>travellist<^>
```
Các cài đặt này thực hiện như sau:

* `Build`: Cấu hình này yêu cầu Docker Compose xây dựng một hình ảnh cục bộ cho `app` dịch vụ, sử dụng đường dẫn và Dockerfile được chỉ định để biết hướng dẫn. Các đối số `user` và `uid` được đưa vào Dockerfile để tùy chỉnh các lệnh tạo của người dùng tại thời điểm xây dựng.
* `Image`: Tên sẽ được sử dụng cho hình ảnh đang được build.
* `Container_name`: Thiết lập tên vùng chứa cho dịch vụ này.
* `restart`: Luôn khởi động lại, trừ khi dịch vụ bị dừng.
* `working_dir`: Đặt thư mục mặc định cho dịch vụ này là `/ var / www`.
* `volume`: Tạo một volume dùng chung sẽ đồng bộ hóa nội dung từ thư mục hiện tại sang `/ var / www` bên trong vùng chứa. Lưu ý rằng đây không phải là thư mục gốc chứa tài liệu của bạn, vì nó sẽ nằm trong vùng chứa `nginx`.
* `networks`: Thiết lập dịch vụ này để sử dụng mạng có tên là `travellist`.

### Dịch vụ `nginx`
Dịch vụ `nginx` sử dụng Nginx image được dựng sẵn trên đỉnh Alpine - một bản phân phối Linux nhẹ. Nó tạo một vùng chứa có tên là `travellist-nginx` và nó sử dụng định nghĩa các cổng để tạo các chuyển hướng từ cổng `8000` trên hệ thống máy chủ sang cổng `80` bên trong vùng chứa.

Bao gồm định nghĩa dịch vụ sau trong nút dịch vụ của bạn, ngay sau dịch vụ `db`:
```nginx
[label /docker-compose.yml]
db:
    image: <^>mysql:5.7<^>
    container_name: <^>travellist-db<^>
    restart: unless-stopped
    environment:
      MYSQL_DATABASE: <^>${DB_DATABASE}<^>
      MYSQL_ROOT_PASSWORD: <^>${DB_PASSWORD}<^>
      MYSQL_PASSWORD: <^>${DB_PASSWORD}<^>
      MYSQL_USER:<^> ${DB_USERNAME}<^>
      SERVICE_TAGS: dev
      SERVICE_NAME: mysql
    volumes:
      - <^>./docker-compose/mysql:/docker-entrypoint-initdb.d<^>
    networks:
      - travellist
```
Các cài đặt này thực hiện như sau:
* `Image`: Xác định hình ảnh Docker sẽ được sử dụng cho vùng chứa này. Trong trường hợp này, chúng tôi đang sử dụng hình ảnh Alpine Nginx 1.17.
* `container_name`: Thiết lập tên vùng chứa cho dịch vụ này: **travellist-nginx**.
* `restart`: Luôn khởi động lại dịch vụ này, trừ khi nó bị dừng một cách rõ ràng.
* `port`: Thiết lập chuyển hướng cổng sẽ cho phép truy cập bên ngoài qua cổng `8000` đến máy chủ web đang chạy trên cổng `8`0 bên trong vùng chứa.
* `volume`: Tạo hai tập dùng chung. Cái đầu tiên sẽ đồng bộ hóa nội dung từ thư mục hiện tại sang `/ var / www` bên trong vùng chứa. Bằng cách này, khi bạn thực hiện các thay đổi cục bộ đối với tệp ứng dụng, chúng sẽ nhanh chóng được phản ánh trong ứng dụng đang được cung cấp bởi `Nginx` bên trong vùng chứa. Tập thứ hai sẽ đảm bảo rằng tệp cấu hình `Nginx` nằm tại` docker-compos / nginx / travellist.conf`, được sao chép vào thư mục cấu hình `Nginx` của vùng chứa.
* `Networks` :Thiết lập dịch vụ này để sử dụng mạng có tên là `travellist`.

### Hoàn thành tệp `docker-compose.yml`
Đây là cách tệp `docker-compo.yml` đã hoàn thành, nó sẽ trông giống như sau:
```nginx
[label docker-compose.yml]
version: "3.7"
services:
  <^>app<^>:
    build:
      args:
        user: sammy
        uid: 1000
      context: ./
      dockerfile: Dockerfile
    image: travellist
    container_name: <^>travellist-app<^>
    restart: unless-stopped
    working_dir: /var/www/
    volumes:
      - ./:/var/www
    networks:
      - travellist

 <^> db<^>:
    image: mysql:5.7
    container_name: <^>travellist-db<^>
    restart: unless-stopped
    environment:
      MYSQL_DATABASE: ${DB_DATABASE}
      MYSQL_ROOT_PASSWORD: ${DB_PASSWORD}
      MYSQL_PASSWORD: ${DB_PASSWORD}
      MYSQL_USER: ${DB_USERNAME}
      SERVICE_TAGS: dev
      SERVICE_NAME: mysql
    volumes:
      - ./docker-compose/mysql:/docker-entrypoint-initdb.d
    networks:
      - travellist

  <^>nginx<^>:
    image: nginx:alpine
    container_name: <^>travellist-nginx<^>
    restart: unless-stopped
    ports:
      - 8000:80
    volumes:
      - ./:/var/www
      - ./docker-compose/nginx:/etc/nginx/conf.d/
    networks:
      - travellist

networks:
  travellist:
    driver: bridge
```
Đảm bảo bạn lưu tệp khi hoàn tất.

## Bước 6: Chạy ứng dụng với Docker Compose
Bây giờ, chúng tôi sẽ sử dụng các lệnh d`docker-compose ` để xây dựng hình ảnh ứng dụng và chạy các dịch vụ mà chúng tôi đã chỉ định trong thiết lập của mình.
Xây dựng hình ảnh ứng dụng bằng lệnh sau:
```custom_prefix($)
docker-compose build app
```

Lệnh này có thể mất vài phút để hoàn thành. Bạn sẽ thấy đầu ra tương tự như sau:
```
[secondary_label Output]
Building app
Step 1/11 : FROM php:7.4-fpm
 ---> fa37bd6db22a
Step 2/11 : ARG user
 ---> Running in f71eb33b7459
Removing intermediate container f71eb33b7459
 ---> 533c30216f34
Step 3/11 : ARG uid
 ---> Running in 60d2d2a84cda
Removing intermediate container 60d2d2a84cda
 ---> 497fbf904605
Step 4/11 : RUN apt-get update && apt-get install -y     git     curl     libpng-dev     libonig-dev     ...
Step 7/11 : COPY --from=composer:latest /usr/bin/composer /usr/bin/composer
 ---> e499f74896e3
Step 8/11 : RUN useradd -G www-data,root -u $uid -d /home/$user $user
 ---> Running in 232ef9c7dbd1
Removing intermediate container 232ef9c7dbd1
 ---> 870fa3220ffa
Step 9/11 : RUN mkdir -p /home/$user/.composer &&     chown -R $user:$user /home/$user
 ---> Running in 7ca8c0cb7f09
Removing intermediate container 7ca8c0cb7f09
 ---> 3d2ef9519a8e
Step 10/11 : WORKDIR /var/www
 ---> Running in 4a964f91edfa
Removing intermediate container 4a964f91edfa
 ---> 00ada639da21
Step 11/11 : USER $user
 ---> Running in 9f8e874fede9
Removing intermediate container 9f8e874fede9
 ---> fe176ff4702b

Successfully built fe176ff4702b
Successfully tagged travellist:latest
```
Khi quá trình xây dựng hoàn tất, bạn có thể chạy môi trường ở chế độ nền với:
```custom_prefix($)
docker-compose up -d
```
```
[secondary_label Output]
Creating travellist-db    ... done
Creating travellist-app   ... done
Creating travellist-nginx ... done
```

Điều này sẽ chạy các vùng chứa của bạn trong nền. Để hiển thị thông tin về trạng thái của các dịch vụ đang hoạt động của bạn, hãy chạy:
```custom_prefix($)
docker-compose ps
```
Bạn sẽ thấy đầu ra như thế này:
```
[secondary_label Output]
 Name                    Command               State          Ports        
--------------------------------------------------------------------------------
<^>travellist-app<^>     docker-php-entrypoint php-fpm    Up      9000/tcp            
<^>travellist-db <^>     docker-entrypoint.sh mysqld      Up      3306/tcp, 33060/tcp 
<^>travellist-nginx<^>   /docker-entrypoint.sh ngin ...   Up      0.0.0.0:8000->80/tcp
```

Môi trường của bạn hiện đã được thiết lập và đang chạy, nhưng chúng tôi vẫn cần thực hiện một vài lệnh để hoàn tất việc thiết lập ứng dụng. Bạn có thể sử dụng lệnh `docker-compile Operating` để thực thi các lệnh trong vùng chứa dịch vụ, chẳng hạn như `ls -l` để hiển thị thông tin chi tiết về các tệp trong thư mục ứng dụng:
```custom_prefix($)
docker-compose exec app ls -l
```
```
[secondary_label Output]
total 260
-rw-rw-r--  1 sammy sammy    737 Jun  9 11:19 Dockerfile
-rw-rw-r--  1 sammy sammy    101 Jan  7 08:05 README.md
drwxrwxr-x  6 sammy sammy   4096 Jan  7 08:05 app
-rwxr-xr-x  1 sammy sammy   1686 Jan  7 08:05 artisan
drwxrwxr-x  3 sammy sammy   4096 Jan  7 08:05 bootstrap
-rw-rw-r--  1 sammy sammy   1501 Jan  7 08:05 composer.json
-rw-rw-r--  1 sammy sammy 179071 Jan  7 08:05 composer.lock
drwxrwxr-x  2 sammy sammy   4096 Jan  7 08:05 config
drwxrwxr-x  5 sammy sammy   4096 Jan  7 08:05 database
drwxrwxr-x  4 sammy sammy   4096 Jun  9 11:19 docker-compose
-rw-rw-r--  1 sammy sammy    965 Jun  9 11:27 docker-compose.yml
-rw-rw-r--  1 sammy sammy   1013 Jan  7 08:05 package.json
-rw-rw-r--  1 sammy sammy   1405 Jan  7 08:05 phpunit.xml
drwxrwxr-x  2 sammy sammy   4096 Jan  7 08:05 public
-rw-rw-r--  1 sammy sammy    273 Jan  7 08:05 readme.md
drwxrwxr-x  6 sammy sammy   4096 Jan  7 08:05 resources
drwxrwxr-x  2 sammy sammy   4096 Jan  7 08:05 routes
-rw-rw-r--  1 sammy sammy    563 Jan  7 08:05 server.php
drwxrwxr-x  5 sammy sammy   4096 Jan  7 08:05 storage
drwxrwxr-x  4 sammy sammy   4096 Jan  7 08:05 tests
drwxrwxr-x 41 sammy sammy   4096 Jun  9 11:32 vendor
-rw-rw-r--  1 sammy sammy    538 Jan  7 08:05 webpack.mix.js
```

Bây giờ chúng tôi sẽ chạy `composer install` để cài đặt các phần phụ thuộc của ứng dụng:
```custom_prefix($)
docker-compose exec app composer install
```

Bạn sẽ thấy đầu ra như sau:
```
[secondary_label Output]
Loading composer repositories with package information
Installing dependencies (including require-dev) from lock file
Package operations: 85 installs, 0 updates, 0 removals
  - Installing doctrine/inflector (1.3.1): Downloading (100%)         
  - Installing doctrine/lexer (1.2.0): Downloading (100%)         
  - Installing dragonmantank/cron-expression (v2.3.0): Downloading (100%)         
  - Installing erusev/parsedown (1.7.4): Downloading (100%)         
  - Installing symfony/polyfill-ctype (v1.13.1): Downloading (100%)         
  - Installing phpoption/phpoption (1.7.2): Downloading (100%)         
  - Installing vlucas/phpdotenv (v3.6.0): Downloading (100%)         
  - Installing symfony/css-selector (v5.0.2): Downloading (100%)             
…
Generating optimized autoload files
> Illuminate\Foundation\ComposerScripts::postAutoloadDump
> @php artisan package:discover --ansi
Discovered Package: facade/ignition
Discovered Package: fideloper/proxy
Discovered Package: laravel/tinker
Discovered Package: nesbot/carbon
Discovered Package: nunomaduro/collision
Package manifest generated successfully.
```
Điều cuối cùng chúng ta cần làm trước khi kiểm tra ứng dụng là tạo một khóa ứng dụng duy nhất bằng công cụ dòng lệnh Laravel `artisan`. Khóa này được sử dụng để mã hóa phiên người dùng và dữ liệu nhạy cảm khác:
```custom_prefix($)
docker-compose exec app php artisan key:generate
```
```
[secondary_label Output]
Application key set successfully.
```
Bây giờ, hãy truy cập trình duyệt của bạn và truy cập tên miền hoặc địa chỉ IP của máy chủ trên cổng 8000:
```info
http://server_domain_or_IP:8000
```
<$>[note]
**Chú ý:** Trong trường hợp bạn đang chạy bản demo này trên máy cục bộ của mình, hãy sử dụng `http: // localhost: 8000` để truy cập ứng dụng từ trình duyệt của bạn.
<$>
Bạn sẽ thấy một trang như thế này hiện ra:
![description image](https://media.cloudfly.vn/posts/Cach-cai-dat-va-thiet-lap-Laravel-voi-Docker-Compose-tren-Ubuntu-20-04-1.png)
Bạn có thể sử dụng lệnh `logs` để kiểm tra nhật ký được tạo bởi các dịch vụ của bạn:
```custom_prefix($)
docker-compose logs nginx
```

```info
Attaching to <^>travellist-nginx<^>
…
travellist-nginx | /docker-entrypoint.sh: Launching /docker-entrypoint.d/20-envsubst-on-templates.sh
travellist-nginx | /docker-entrypoint.sh: Configuration complete; ready for start up
travellist-nginx | 192.168.0.1 - - [09/Jun/2020:11:46:34 +0000] "GET / HTTP/1.1" 200 627 "-" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.61 Safari/537.36"
travellist-nginx | 192.168.0.1 - - [09/Jun/2020:11:46:35 +0000] "GET / HTTP/1.1" 200 627 "-" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.61 Safari/537.36"
```
Nếu bạn muốn tạm dừng môi trường Docker Compose của mình trong khi vẫn giữ trạng thái của tất cả các dịch vụ của nó, hãy chạy:
```custom_prefix($)
docker-compose pause
```
```
[secondary_label Output]
Pausing travellist-db    ... done
Pausing travellist-nginx ... done
Pausing travellist-app   ... done
```
Sau đó, bạn có thể tiếp tục các dịch vụ của mình với:
```custom_prefix($)
docker-compose unpause
```
```
[secondary_label Output]
Unpausing travellist-app   ... done
Unpausing travellist-nginx ... done
Unpausing travellist-db    ... done
```

Để tắt môi trường Docker Compose và xóa tất cả các vùng chứa, mạng và khối lượng của nó, hãy chạy:
```custom_prefix($)
docker-compose down
```
```
[secondary_label Output]
Stopping travellist-nginx ... done
Stopping travellist-db    ... done
Stopping travellist-app   ... done
Removing travellist-nginx ... done
Removing travellist-db    ... done
Removing travellist-app   ... done
Removing network travellist-laravel-demo_travellist
```

## Kết luận
Trong hướng dẫn này, chúng tôi đã thiết lập môi trường Docker với ba vùng chứa bằng Docker Compose để xác định cơ sở hạ tầng của chúng tôi trong tệp YAML.

Từ thời điểm này, bạn có thể làm việc trên ứng dụng Laravel của mình mà không cần cài đặt và thiết lập máy chủ web cục bộ để phát triển và thử nghiệm. Hơn nữa, bạn sẽ làm việc với môi trường dùng một lần có thể dễ dàng sao chép và phân phối, điều này có thể hữu ích trong khi phát triển ứng dụng của bạn và cả khi hướng tới môi trường sản xuất.
