Introduction
- File này hướng dẫn build container cho: app - laravel, client - vuejs, mysql, nginx, swagger (tuỳ chọn), rector trong docker
- Hướng dẫn sử dụng lệnh cơ bản sử dụng PHPstan để kiểm tra quy ước code và Rector để kiểm tra chất lượng code Docker build container Docker build container
- version 1.0 : https://github.com/dtvn-training/linebot/tree/v1
- version 2.0 : https://github.com/dtvn-training/linebot/tree/v2
Part 1. Container Mysql
1.1 Step by step
- Docker-compose.yml of container mysql
- Để xây dựng được container mysql nhằm quản lí dữ liệu của project ta sử dụng image: mysql/mysql-server:8.0 .
- Vì container này khá đơn giản và ngắn gọn nên ta không cần dùng đến Dockerfile
- Đoạn code để xây dựng container như sau, docker-compose.yml:
mysql: container_name: mysql image: mysql/mysql-server:8.0 restart: unless-stopped tty: true ports: - "3309:3306" environment: MYSQL_DATABASE: linebot MYSQL_USER: hivanmanh MYSQL_PASSWORD: hivanmanh MYSQL_ROOT_PASSWORD: hivanmanh SERVICE_TAGS: dev SERVICE_NAME: mysql networks: - laravel
- Giải thích
- container_name: mysql : Tên của container
- restart: unless-stopped : Xác định chế độ khởi động lại của container trong trường hợp container tắt
- tty: true : Thiết lập một terminal TTY (TeleTYpewriter) cho container. Trong trường hợp này, một terminal TTY được kích hoạt cho container, cho phép truy cập vào dòng lệnh của container.
-
ports: - "3309:3306"
Ánh xạ cổng 3306 trong container docker ra 3309 ở máy host
-
environment:
MYSQL_DATABASE: linebot MYSQL_USER: hivanmanh MYSQL_PASSWORD: hivanmanh MYSQL_ROOT_PASSWORD: hivanmanh SERVICE_TAGS: dev SERVICE_NAME: mysql
Thêm các biến môi trường cần thiết cho container mysql Sau khi build xong ta sẽ sử dụng các biến này để connect đến database trong container
1.2 Results
Part 2. Container App
2.1 Step by step
- Organize files and folders
- Folder contents chứa mã nguồn của app laravel , phpstan , rector , swagger
- Folder docker chứa các file dockerfile
- php.dockerfile (linebot\docker\php.dockerfile) chứa mã nguồn để xây dựng container app gồm có 2 server là php và composer
- php/php.ini (linebot\docker\php\php.ini) chứa mã nguồn để cấu hình serivce php
- docker-compose.yml of container app
- App laravel cần có php và composer để sử dụng được , ta sẽ sử dụng php:8.1.2-fpm-alpine
- Container này không đơn giản như các container trước nên cần có Docker file (php.dockerfile) để tách code ra cho file docker-compose.yml trở nên ngắn gọn hơn .
- Lưu ý : Trình tự chạy sẽ là : Code trong Dockerfile chạy trước rồi mới đến code ở docker-compose.yml
- Dưới đây là đoạn code docker-compose.yml để build được container app :
app: container_name: app build: context: ./docker dockerfile: php.dockerfile args: - UID=${UID:-1000} - GID=${GID:-1000} ports: - "9000:9000" volumes: - ./contents:/var/www/html:delegated working_dir: /var/www/html tty: true entrypoint: - sh - -c - | composer install && php artisan migrate:refresh --seed && php-fpm -y /usr/local/etc/php-fpm.conf -R networks: - laravel
- Giải thích :
- container_name: app : Tên của container
- Block build:
-
context: ./docker dockerfile: php.dockerfile
● Chỉ định nơi đọc Dockerfile
-
args: - UID=${UID:-1000} - GID=${GID:-1000}
● Truyền biến vào cho Dockerfile trong qúa trình build
-
ports: - "9000:9000"
-
Ánh xạ cổng 9000 trong container PHP-FPM docker ra cổng 9000 ở máy host
-
Volumes:
- ./contents:/var/www/html:delegated
-
Mount (đồng bộ folder contents chứa mã nguồn app của máy host vào folder /var/www/html trong container của docker) với cờ là delegated (ngoài cờ này còn có các cờ cached , consistent)
-
working_dir: /var/www/html : Chỉ định folder làm việc cho container khi chạy các lệnh entrypoint trong docker-compose.yml file
-
tty: true : Giữ cho container luôn chạy , có một cách khác là (entrypoint: ["tail", "-f", "/dev/null"])
-
entrypoint: - sh - -c - | composer install && php artisan migrate:refresh --seed && php-fpm -y /usr/local/etc/php-fpm.conf -R
-
Sử dụng entrypoint để chạy các lệnh cần thiết , sử dụng cờ -sh -c để chạy nhiều lệnh trong entrypoint , composer install để cài các dependencies cho app . php artisan migrate:refresh --seed để chạy lại dữ liệu mỗi khi build (có thể code lệnh này hoặc không)(thường sẽ là không , lệnh này phải tự chạy) Và php-fpm -y /usr/local/etc/php-fpm.conf -R dùng để khởi động PHP-FPM để sử dụng cho container Nginx
- Dockerfile of container app (linebot\docker\php.dockerfile)
FROM php:8.1.2-fpm-alpine ARG UID
ARG GID ENV UID=${UID}
ENV GID=${GID} RUN mkdir -p /var/www/html WORKDIR /var/www/html COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer RUN delgroup dialout RUN addgroup -g ${GID} --system laravel
RUN adduser -G laravel --system -D -s /bin/sh -u ${UID} laravel RUN sed -i "s/user = www-data/user = laravel/g" /usr/local/etc/php-fpm.d/www.conf
RUN sed -i "s/group = www-data/group = laravel/g" /usr/local/etc/php-fpm.d/www.conf
RUN echo "php_admin_flag[log_errors] = on" >> /usr/local/etc/php-fpm.d/www.conf RUN docker-php-ext-install pdo pdo_mysql USER laravel CMD ["php-fpm", "-y", "/usr/local/etc/php-fpm.conf", "-R"]
- Php configuration file (line\docker\php\php.ini) : file để cấu hình php
2.2 Results
docker ps (xem các container đang chạy) docker exec -it app sh (đi vào container app để thực hiện câu lệnh) Từ đây ta có thể sử dụng : composer , php , php artisan để thực hiện các việc liên quan đến app .
Part 3. Container Nginx
3.1 Step by step
-
Intro : Ta đã có container mysql để thao tác và lưu trữ giữ liệu của project , container app để có thể sử dụng các lệnh của php , artisan và composer lên mã nguồn của project. Giờ ta cần cho project hiển thị ra ngoài giống như bình thường ta run project laravel vậy . Để làm điều đó thì sử dụng container Nginx .
-
Organize files and folders
- docker-compose.yml chứa đoạn code để build container nginx
nginx: container_name: nginx build: context: ./docker dockerfile: nginx.dockerfile args: - UID=${UID:-1000} - GID=${GID:-1000} ports: - "99:80" volumes: - ./contents:/var/www/html:delegated depends_on: - app - mysql networks: - laravel
- Giải thích :
- container_name: nginx : Tên container
- Khối đế build container nginx : build: context: ./docker dockerfile: nginx.dockerfile args: - UID={GID:-1000}
- ports:
- "99:80"
- Ánh xạ cổng 80 của container ra cổng 99 ở máy host
- volumes:
- ./contents:/var/www/html:delegated
- Mont (đồng bộ folder contents của máy host và folder var/www/html của container docker)
- depends_on:
- app
- mysql
-
Phụ thuộc vào container app và mysql , chờ app và mysql build xong rồi mới đến app
-
folder docker chứa các file dockerfile cần thiết
-
linebot\docker\nginx.dockerfile
FROM nginx:stable-alpine ARG UID
ARG GID ENV UID=${UID}
ENV GID=${GID} RUN delgroup dialout RUN addgroup -g ${GID} --system laravel
RUN adduser -G laravel --system -D -s /bin/sh -u ${UID} laravel
RUN sed -i "s/user nginx/user laravel/g" /etc/nginx/nginx.conf ADD ./nginx/default.conf /etc/nginx/conf.d/ RUN mkdir -p /var/www/html
- linebot\docker\nginx\default.conf
server { listen 80; index index.php index.html; server_name _; root /var/www/html/public; client_max_body_size 100M; location / { try_files $uri $uri/ /index.php?$query_string; } location ~ \.php$ { try_files $uri =404; fastcgi_split_path_info ^(.+\.php)(/.+)$; fastcgi_pass app:9000; # app:9000 is name service app in docker-compose.yml fastcgi_index index.php; include fastcgi_params; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; fastcgi_param PATH_INFO $fastcgi_path_info; fastcgi_param PHP_VALUE "post_max_size=100M\nupload_max_filesize=100M"; }
}
- Giải thích :
- Khối server dùng để cấu hình cho máy chủ Nginx
- listen 80; : Lắng nghe cổng 80 trong container
- root /var/www/html/public; : Chỉ định folder gốc cho máy chủ , đây là folder mà nginx sẽ tìm kiếm các file
- index index.php index.html; : nginx sẽ tìm kiếm file index.php đầu tiên nếu không có sẽ tìm kiếm file index.html
- client_max_body_size 100M; : kích thước tối đa cho một yêu cầu từ phía client cho máy chủ nginx
- post_max_size=100M\nupload_max_filesize=100M : kích thước tối đa mà client có thể upload lên
3.2 Results
- Goto : http://localhost:99/
Part 4. Container Client Vue3js
4.1 Step by step
- Organize files and folders
- Folder linebot chứa toán bộ mã nguồn của dự án bao gồm cả docker file và folder contents
- Folder contents chứa mã nguồn của ứng dựng gồm mã nguồn laravel , rector , client , phpstan , swagger
- Folder client chứa mã nguồn của vuejs
- Docker-compose.yml of container client
- Để tạo được container client ta sử dụng image node:18.14.2 để cài đặt npm và các Dependencies
- Lưu ý : Ta có thể code trực tiếp vào docker-compose.yml hoặc có thể tách ra thành nhiều file ví dụ như Dockerfile để cho gọn file docker-compose.yml , do container này khá là ngắn gọn nên chỉ cần code ở docker-compose.yml là được .
- Code đoạn code sau đây vào file linebot/docker-compose.yml
client: image: node:18.14.2 container_name: client volumes: - ./contents/client:/var/www/html/client:delegated ports: - "8089:8080" working_dir: /var/www/html/client/ entrypoint: - sh - -c - | npm install && npm run serve && tail -f /dev/null networks: - laravel
- Giải thích
- image: node:18.14.2 : Ta sử dụng nodejs version 18.14.2
- container_name: client : Tên container , nếu như ta không đặt thì docker sẽ tự động đặt bằng [project_name]-[container_name]-nth
- volumes:
- ./contents/client:/var/www/html/client:delegated ● Dùng để mount (đồng bộ) giữa folder ở máy host và folder trong container của docker , hiện tại nó đang đồng bộ giữa folder ./contents/client ở máy host và folder /var/www/html/client trong container của docker . Lưu ý là ta hoàn toàn có thể đặt một tên khác cho folder trong container của docker , ta đặt tên gì cũng được (tránh đặt các tên trùng với tên từ khóa trong folder container docker) ● Ở đây ta sử dụng cờ delegated để đồng bộ , ngoài cờ này ra thì còn có các cờ : cached , consistent
- ports:
- "8089:8080" Ở đây 8089 chính là host port và 8080 chính là container port
- working_dir: /var/www/html/client/ Chỉ định thư mục làm việc là folder này trong container , đây chính là folder ta mount vào để chứa mã nguồn vuejs trong container . Các câu lệnh sẽ được chạy tại thư mục này
- entrypoint:
- sh
- -c
- | npm install && npm run serve && tail -f /dev/null Sử dụng entrypoint để chạy các câu lệnh cài đặt các dependencies của vuejs và lệnh run serve . Ở đây ta sử dụng 2 cờ là -sh và -c để chạy được nhiều lệnh trong entrypoint .
- Lưu ý : (Đọc thêm) Nếu có xảy ra các lỗi sau :
- Fix lỗi Hot reload Vuejs : Mặt dù ta đã mount giữa folder máy host và folder trong container trong docker , khi ta thay đổi code ở folder máy host thì các code trong folder của container docker cũng thay đổi nhưng nó không tự động build lại để load ra lại cái mới . Cách fix như sau :
+ linebot\contents\client\vue.config.js : const { defineConfig } = require('@vue/cli-service')
module.exports = defineConfig({ transpileDependencies: true, configureWebpack: { entry: "./src/main.js", devServer: { hot: true, }, watch: true, watchOptions: { ignored: /node_modules/, poll: 500, }, },
})
- Giải thích
- Quan sát sự thay đổi của mã nguồn với thời gian là 500ms (không quan sát node_modules)
watchOptions: { ignored: /node_modules/, poll: 500, },
- Bật chất độ hot reload
devServer: { hot: true, },
- Lỗi khi thực hiện liên tiếp 2 lệnh : npm install và npm run serve
- Vấn đề xảy ra do lệnh : npm install trong vuejs sau khi chạy xong nó sẽ tự động chạy lệnh npm run build và lệnh npm run serve cũng vậy , sau khi chạy xong nó cũng tự chạy lệnh npm run build , dẫn đến kết quả là có 2 lần build và gây ra lỗi . Cách giải quyết là giờ ta chỉ cho nó build một lần khi chạy npm run serve thôi .
- Ta sẽ bỏ đi dòng này trong package.json
- "postinstall": "npm run build" : Dòng này cho phép npm install xong thì tự động chạy npm run build
- Có thể đây là tính năng , mỗi khi install xong thì nó tự build lại . Ta có thể vẫn giữ tính năng nay bằng cách trong file linebot\contents\client\vue.config.js ta bỏ đi folder node_module , nghĩa là khi node_module có thay đổi gì thì nó quan sát và chạy lại lệnh build cho ta
4.2 Results
Goto : http://localhost:8089/login
4.3 Read more
- [1] Dockerize Vue.js App
- [2] Dockerized Vue app - hot reload does not work
- [3] Using nodemon in Vue3js (đọc thêm)
- [4] npm ci = npm install
- Đọc thêm : Sử dụng nodemon để quan sát sự thay đổi của code và thực hiện lệnh gì đó Linebot\contents\client\nodemon.json :
{ "watch": ["src"], "ext": "js,vue", "exec": "npm run serve"
}
Quan sát sự thay đổi trong folder src thì chạy lệnh “npm run serve” Thực ra ngay vuejs đã có watch sẵn rồi , đây chỉ là trong quá trình fix hot reload thì tìm hiểu thêm .
- Câu lệnh if else trong docker-composer.yml
entrypoint: - sh - -c - | if [ -d "node_modules" ]; then npm run serve else npm install fi
- Nếu có node_modules thì chỉ chạy lệnh npm run serve còn ngược lại thì chạy lệnh npm install
- Các câu lệnh nhập trong docker-compose.yml sẽ được bind ra trong docker như sau , có thể vào cmd của docker để xem . Thử nghiệm sử dụng chúng trong docker-compose.yml thay cho những lệnh ta đã viết ví dụ : thay
entrypoint: - sh - -c - | npm install && npm run serve && tail -f /dev/null
Bằng
"Entrypoint": [ "sh", "-c", "npm install &&\nnpm run serve &&\ntail -f /dev/null\n" ],
Part 5. Container Rector
5.1 Step by step
- Organize files and folders
- Tạo folder tools trong folder contents để chứa những tool sử dụng cho project
- Giải thích : Rector được sử dụng trong laravel nhằm mục đích kiểm tra chất lượng code , để sử dụng rector ta sẽ tạo một container trong đó chứa php và composer nhằm mục đích chạy rector . File tools/rector/rector.php là nơi sẽ viết các rule để kiểm tra chất lượng code . tools/rector.composer.json để khai báo nhằm cài dependencies cho tool rector .
- Linebot\contents\tools\rector\composer.json
{ "require": { "php": "^8.1.2", "rector/rector": "^1.0", "driftingly/rector-laravel": "^1.1" }, "scripts": { "rector-rules": "vendor/bin/rector list-rules", "rector-process": "vendor/bin/rector process /var/www/html/app", "rector-dry": "vendor/bin/rector process /var/www/html/app --dry-run", "rector-dry-debug": "vendor/bin/rector process /var/www/html/app --dry-run --debug" }, "autoload-dev": { "psr-4": { "Utils\\Rector\\": "utils/rector/src", "Utils\\Rector\\Tests\\": "utils/rector/tests" } }
}
- Giải thích :
- Khối require dùng để khai báo để cài dependencies rector và rector-laravel (nhằm mục đích sử dụng các bộ rule của php và cả các bộ rule của laravel)
- Khối scripts dùng để alias cho các lệnh run của rector /var/www/html/app chính là đường dẫn tương đối dẫn đến folder linebot/contents/app
- Ta sẽ có 2 lệnh cơ bản : composer rector-dry dùng để kiểm tra chất lượng code và hiển thị ra những thông báo sau khi đã kiểm tra xong .
- Composer rector-process : Sẽ là lệnh dùng để vừa kiểm tra và vừa tự động sửa những lỗi đó .
- linbot\contents\tools\rector\rector.php
<?php use Rector\Config\RectorConfig;
use Rector\TypeDeclaration\Rector\Property\TypedPropertyFromStrictConstructorRector; return RectorConfig::configure() // register single rule ->withRules([ TypedPropertyFromStrictConstructorRector::class ]) // here we can define, what prepared sets of rules will be applied ->withPreparedSets( deadCode: true, codeQuality: true );
- Giải thích :
- Cấu hình Rector để thực hiện các thay đổi cụ thể trong mã nguồn PHP, bao gồm thêm các kiểu dữ liệu vào các thuộc tính trong các constructor và áp dụng các tập hợp quy tắc chuẩn bị trước để cải thiện chất lượng mã và loại bỏ mã không sử dụng
- Linebot\docker-compose.yml
rector: container_name: rector build: context: ./docker dockerfile: rector.dockerfile args: - UID=${UID:-1000} - GID=${GID:-1000} volumes: - ./contents:/var/www/html working_dir: /var/www/html depends_on: - app tty: true entrypoint: - sh - -c - | cd tools/rector && composer install && tail -f /dev/null networks: - laravel
- Giải thích :
- container_name: rector : Tên container
-
build: context: ./docker dockerfile: rector.dockerfile args: - UID=${UID:-1000} - GID=${GID:-1000}
- Khối build dùng để chỉ định Dockerfile để chạy cho rector và truyền các param vào cho Dockerfile
-
volumes: - ./contents:/var/www/html
- Mount folder contents của máy host vào folder /var/www/html trong container docker
- working_dir: /var/www/html : Chỉ định folder làm việc trong container docker
-
depends_on: - app
- Container rector sẽ phụ thuộc vào container app , đợi container app build xong mới đến container rector
- tty: true : Thiết lập một terminal TTY (TeleTYpewriter) cho container. Trong trường hợp này, một terminal TTY được kích hoạt cho container, cho phép truy cập vào dòng lệnh của container.
-
entrypoint: - sh - -c - | cd tools/rector && composer install && tail -f /dev/null
- Sử dụng cờ -sh và -c để chạy nhiều lệnh cho container rector . Ta có working_dir: /var/www/html nên cần cd tools/rector , sau khi đã đứng tại folder rector thì sử dụng composer install để cài đặt dependencies rector . Cuối cùng sử dụng tail -f /dev/null để giữ cho container luôn được chạy .
- linebo\docker\rector.dockerfile
FROM php:8-fpm-alpine ARG UID
ARG GID ENV UID=${UID}
ENV GID=${GID} RUN mkdir -p /var/www/html WORKDIR /var/www/html COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer RUN delgroup dialout RUN addgroup -g ${GID} --system laravel
RUN adduser -G laravel --system -D -s /bin/sh -u ${UID} laravel RUN sed -i "s/user = www-data/user = laravel/g" /usr/local/etc/php-fpm.d/www.conf
RUN sed -i "s/group = www-data/group = laravel/g" /usr/local/etc/php-fpm.d/www.conf
RUN echo "php_admin_flag[log_errors] = on" >> /usr/local/etc/php-fpm.d/www.conf USER laravel
- Giải thích : Dockerfile của rector nó cũng khá giống với Dockerfile của container app , nó cũng dùng để cài php và compsoer cho container .
5.2 Results
- Run commands : composer rector-dry ; composer rector-process to view results
5.3 Read more
-
Refactoring Laravel facades to Dependency Injection
-
Laravel Beauty: Tìm hiểu về Facade
-
https://github.com/driftingly/rector-laravel (Đọc thêm)
-
Rector - The Power of Automated Refactorin (Rector PDF)
-
Sự khác biệt giữa RUN, CMD và ENTRYPOINT trong Dockerfile
-
Flag - docker compose up
-
How to keep Docker container running after starting services?
-
Note :
-
Mỗi service được build ra sẽ có một folder riêng , mặc dù cùng đặt tên là : /var/www/html ,... nhưng thật ra chúng không giống nhau , chính vì thế ta có thể đặt tên gì cũng được .
-
Nếu các service sử dụng chung work dir và volumes như nhau sẽ giống nhau , tuy nhiên tốn nhiều bộ nhớ volumes:
- ./contents:/var/www/html working_dir: /var/www/html
-
Cách xèm file bằng docker GUI :
Part 6. Container Swagger
6.1 Step by step
- Organize files and folders
- Giải thích việc sử dụng Swagger trong Laravel giúp tạo và quản lý tài liệu API một cách dễ dàng, giảm thời gian và công sức khi phát triển và kiểm thử API, và tạo điều kiện thuận lợi cho việc tích hợp với các công cụ quản lý API khác
- Folder php và apache dùng để cấu hình php và apache của container swagger
- Cách sử dụng Swagger tham khảo chi tiết ở file : Using Swagger in Laravel . Còn dưới đây là cách xây dựng container swagger
- Tham khảo mã nguồn build container từ github của Swagger
- L5-Swagger /docker-compose.yml
- L5-Swagger /Dockerfile
- L5-Swagger/docker /apache/
- L5-Swagger/docker /php/
- Service l5-swagger-app in docker-compose.yml file :
l5-swagger-app: image: l5-swagger-app container_name: swagger restart: "no" build: args: user: l5-swagger uid: 1000 context: ./docker dockerfile: swagger.dockerfile target: local volumes: - ./contents:/app/l5-swagger-app:rw ports: - "7777:80" depends_on: - mysql - app - rector - client networks: - laravel
- Giải thích :
- image: l5-swagger-app : Tên image của container
- container_name: swagger : Tên của container
- restart: "no" : Chỉ định container không tự động khởi động lại nếu có lỗi , mình phải tự khởi động nó lại
-
build: args: user: l5-swagger uid: 1000 context: ./docker dockerfile: swagger.dockerfile target: local
- Khối build dùng để chỉ định Dockerfile để build container swagger
-
volumes: - ./contents:/app/l5-swagger-app:rw
- Mount folder của máy host và folder của container trong docker
- rw là viết tắt của read , write . cấp quyền đọc và ghi cho folder . (Đọc thêm về sự khác biệt giữa cờ delegated và rw)
-
ports: - "7777:80"
- Ánh xạ cổng 80 của container docker ra cổng 7777 của máy host
-
depends_on: - mysql - app - rector - client
- Chỉ định những container phụ thuộc , đợi những container này build xong thì container swagger mới tiến hành build
- linebot\docker\swagger.dockerfile
FROM php:8.1-apache-bullseye as base
LABEL vendor="L5 Swagger"
ARG user
ARG uid
ENV TZ="UTC" RUN apt-get update && apt-get install -y \ git \ curl \ libpng-dev \ libonig-dev \ libxml2-dev \ zip \ unzip memcached libmemcached-dev libmemcached-tools nano RUN apt-get clean && rm -rf /var/lib/apt/lists/* #+++
RUN apt-get update --fix-missing -q \ && apt-get install -y curl mcrypt gnupg build-essential software-properties-common wget vim zip unzip libxml2-dev libz-dev libpng-dev libmemcached-dev \ && pecl install memcached \ && docker-php-ext-enable memcached
RUN pecl install -f xdebug \ && docker-php-ext-enable xdebug RUN a2enmod rewrite
COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer
COPY --chown=root:root php/php.ini /usr/local/etc/php/php.ini
COPY --chown=root:root apache/000-default.conf /etc/apache2/sites-available/000-default.conf
COPY --chown=www-data:www-data . /app
RUN sed -ri -e 's!/var/www/html!${APACHE_DOCUMENT_ROOT}!g' /etc/apache2/sites-available/*.conf
RUN sed -ri -e 's!/var/www/!${APACHE_DOCUMENT_ROOT}!g' /etc/apache2/apache2.conf /etc/apache2/conf-available/*.conf
RUN useradd -G www-data,root -u $uid -d /home/$user $user
RUN mkdir -p /home/$user/.composer && \ chown -R $user:$user /home/$user
RUN chown -R $user:$user /app
WORKDIR /app
USER $user
RUN alias composer='/usr/local/bin/php -dxdebug.mode=off /usr/local/bin/composer'
RUN /usr/local/bin/php -dxdebug.mode=off /usr/local/bin/composer create-project laravel/laravel l5-swagger-app --no-interaction
WORKDIR /app/l5-swagger-app
RUN /usr/local/bin/php -dxdebug.mode=off /usr/local/bin/composer config repositories.l5-swagger path '../'
RUN /usr/local/bin/php -dxdebug.mode=off /usr/local/bin/composer require 'darkaonline/l5-swagger:dev-master'
RUN chown -R $user:$user .
FROM base as local
ENV PHP_IDE_CONFIG="serverName=l5-swagger"
ENV APP_ENV="local"
ENV APACHE_DOCUMENT_ROOT="/app/l5-swagger-app/public"
ENV L5_SWAGGER_GENERATE_ALWAYS="true"