docker-compose does not create none-existing variable in .env file - laravel

This is a setup for laravel project:
Dockerfile:
FROM php:8.1.2-cli-buster
COPY --from=composer /usr/bin/composer /usr/bin/composer
RUN apt-get update && apt install git -y
WORKDIR /var/www/html
COPY . .
RUN composer install --no-dev
RUN mv ./.env.example .env
RUN php artisan key:generate
CMD ["/bin/bash", "-c", "php artisan serve --host 0.0.0.0 --port 8000"]
Look at this variable inside docker-compse.yml
version: "3.8"
services:
artisan:
build: .
environment:
CUSTOM_VAR: custom-value-from-compse
ports:
- '8000:8000'
api.php
Route::get('test', function () {
dump(env('CUSTOM_VAR')); //CUSTOM_VAR is null
});
The above route should dump custom-value-from-compse value but it dumpnull, What is the problem here ? It only overide existing variable in .env file, I mean if i set CUSTOM_VAR in .env file to 'some-value' it does not override it to the value inside of the docker compose
Note: the CUSTOM_VAR wil be null even i put it in Dockerfile...

Maybe try this:
version: "3.8"
services:
artisan:
build: .
environment:
# laravel uses Dotenv to set and load environment variables,by default it will not
# overwrite existing environment variables. So we set env variables for app container here
# then laravel will use these env values instead of the same env variables defined in .env file.
- "CUSTOM_VAR=custom-value-from-compse"
ports:
- '8000:8000'
Source: https://gist.github.com/kevinyan815/fa0760902d29f19a4213b4a16fe0501b#file-docker-compose-yml-for-laravel-L11

You can set default values for variables in docker-compose file. If variables in .env file doesn't exist the default value will be set, otherwise it will be override it to the value inside of the docker compose.
version: "3.8"
services:
artisan:
build: .
environment:
- CUSTOM_VAR=${CUSTOM_VAR_FROM_ENV_FILE:-custom-value-from-compse}
https://docs.docker.com/compose/environment-variables/

Related

Docker-compose custom .env file unexpected behaviour

Example
Consider this example docker-compose file with custom .env file:
version: '3'
services:
service_example:
build:
dockerfile: Dockerfile
context: .
args:
AAA: ${AAA}
command: python3 src/service/run.py
env_file:
- custom_env.env
custom_env.env:
AAA=qqq
When I run docker-compose config I get the following output:
WARNING: The AAA variable is not set. Defaulting to a blank string.
services:
service_example:
build:
args:
AAA: '' <----------------------------- ??????
context: /Users/examples
dockerfile: Dockerfile
command: python3 src/service/run.py
environment:
AAA: qqq
version: '3'
Question
Why AAA is unset in build section?
What should I do to set it properly (to the value provided from custom file: AAA=qqq)?
I've also noticed that if I change the env file name to the default setting mv custom_env.env .env and remove env_file section from docker-compose.yml - everything will be just fine:
services:
service_example:
build:
args:
AAA: qqq
context: /Users/examples
dockerfile: Dockerfile
command: python3 src/service/run.py
version: '3'
Quick Answer
docker-compose --env-file custom_env.env config
Answers Explanation
Question-1: Why AAA is unset in build section?
Because the env file specified in env_file property custom_env.env is specific for the Container only, i.e. those variables are to be passed to container while running not during image build.
Question-2: What should I do to set it properly (to the value provided from custom file: AAA=qqq)?
To provide environment variables for build step in docker-compose file using custom env file, we need to specify the custom file path. Like
Syntax: docker-compose --env-file FILE_PATH config
Example: docker-compose --env-file custom_env.env config
Question-3: How .env works?
Because that is the default file for which docker-compose looks for.
Summary
So, In docker-compose for current scenario we can consider 2 stages for specifying env
Build Stage(Image)
Running Stage(Container)
For Build stage - we can use .env default file or we can use --env-file option to specify custom env file
For Running Stage - we can specify environment variables using environment: property or we can use env_file: property to specify a env file
References
https://docs.docker.com/compose/env-file/
https://docs.docker.com/compose/environment-variables/
https://docs.docker.com/compose/compose-file/#env_file
https://docs.docker.com/compose/compose-file/#environment

How to run db migration when Laravel container is up?

I have problem with running db migration on when container is up.
Problems:
cant set app key because gitlab-ci didn't copy .env file (getting err in gitlab ci console), so setting key needs to happen later
running migration with wait-for-it because container exits with success code 0 (migrations is up)
I will put code only for my db and web container.
db:
container_name: db
image: mysql:5.7.22
restart: unless-stopped
environment:
MYSQL_DATABASE: ${DB_DATABASE}
MYSQL_USER: ${DB_USERNAME}
MYSQL_ROOT_PASSWORD: ${DB_PASSWORD}
MYSQL_PASSWORD: ${DB_PASSWORD}
ports:
- 3306:3306
volumes:
- mysql-data:/var/lib/mysql
networks:
- my-network
backend:
image: registry image
container_name: "backend"
build:
context: ./backend
dockerfile: Dockerfile
depends_on:
- db
ports:
- 1020:80
networks:
- my-network
gitlab-ci:
build-backend:
tags:
- vps
variables:
GIT_CLEAN_FLAGS: none
stage: dockerize
image: docker:latest
services:
- docker:dind
dependencies: []
script:
- docker build -t backend backend
- cp .env ./backend/.env
- cd backend
- docker build -t $CI_REGISTRY_IMAGE/backend:$CI_COMMIT_BRANCH .
- docker tag $CI_REGISTRY_IMAGE/backend:$CI_COMMIT_BRANCH $CI_REGISTRY_IMAGE/frontend:$CI_COMMIT_REF_NAME
- docker login -u gitlab-ci-token -p $CI_JOB_TOKEN $CI_REGISTRY
- docker push $CI_REGISTRY_IMAGE/backend:$CI_COMMIT_REF_NAME
...deploying code
I'm using https://github.com/vishnubob/wait-for-it
Dockerfile:
FROM webdevops/php-nginx:7.4-alpine
# Install Laravel framework system requirements (https://laravel.com/docs/8.x/deployment#optimizing-configuration-loading)
RUN apk add oniguruma-dev postgresql-dev libxml2-dev
RUN docker-php-ext-install \
bcmath \
ctype \
fileinfo \
json \
mbstring \
pdo_mysql \
pdo_pgsql \
tokenizer \
xml
# Copy Composer binary from the Composer official Docker image
COPY --from=composer:latest /usr/bin/composer /usr/bin/composer
ENV WEB_DOCUMENT_ROOT /var/www/html/public
ENV APP_ENV production
WORKDIR /var/www/html
COPY . .
RUN composer install --no-interaction --optimize-autoloader
RUN chown -R root:root .
RUN chmod -R ugo+rw storage
RUN chmod 777 wait-for-it.sh
RUN chmod 777 migrate.sh
EXPOSE 80
CMD ["./wait-for-it.sh", "db:3306", "--", "./migrate.sh"]
migrate.sh:
#!/bin/sh
php artisan key:generate
# Optimizing Configuration loading
php artisan config:cache
# Optimizing Route loading
php artisan route:cache
# Optimizing View loading
php artisan view:cache
echo "finished cashes"
php artisan migrate --force &
exec "$#"
So how can I solve exit code 0, meant to say how to prevent container from stopping?
Thanks
Solution is to use Supervisor which is useful for having all the jobs in background and wont close your container while running migrations.
I can't believe that this configuration from this repo is working perfectly it saves my time. I spent more than 7 days in searching for the best solution, but this guy who posted this saves me!
Refer to this repo please https://github.com/harshalone/laravel-9-production-ready
I didn't have to change a line of code, hope you don't have too. Simply works!
for anyone struggling with running migrations but your database isn't up before your Laravel application, just want to mention that I've used wait-for-it script and changed last line of code in my Dockerfile like this:
CMD ["/var/www/docker/wait-for-it.sh", "db:3306", "--", "/var/www/docker/run.sh"]
So now my migrations will first wait for database to be up and running.
Just put wait-for-it.sh inside of your docker folder or use it from github directly.

docker compose and swarm for laravel app in production

everyone, I am confused I am new to the DevOps world and I have no idea how to use docker-compose or swarm in production I mean what are the best practices in production for both I followed up with this article on the digital ocean How To Install and Set Up Laravel with Docker Compose on Ubuntu 20.04
all works like a charm in local, test, and dev environments, and I tried to take this to the next step for production env, and I noticed some things should be changed for production mode like so
Removing any volume bindings for application code, so that code stays inside the container and can’t be changed from outside.
Binding to different ports on the host. check the link for more info use compose in production
I don't know how to achieve #1 point
here's my DockerFile below to build my custom laravel image and docker-compose for my services
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 \
curl \
libpng-dev \
libonig-dev \
libxml2-dev \
zip \
unzip
# Clear cache
RUN apt-get clean && rm -rf /var/lib/apt/lists/*
# Download php extension installer
ADD https://github.com/mlocati/docker-php-extension-installer/releases/latest/download/install-php-extensions /usr/local/bin/
# Give php extension installer a permission
RUN chmod +x /usr/local/bin/install-php-extensions
# Install php extensions via php extension installer
RUN install-php-extensions zip
# 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/html
USER $user
version: "3.7"
services:
app:
build:
args:
user: sammy
uid: 1000
context: ./
dockerfile: Dockerfile
image: app
container_name: app
restart: always
working_dir: /var/www/html
volumes:
- ./:/var/www/html
networks:
- backend
db:
image: mysql:8.0
container_name: db
restart: always
environment:
MYSQL_DATABASE: ROUTE
MYSQL_ROOT_PASSWORD: 2020
MYSQL_PASSWORD: 2020
MYSQL_USER: sqluser
volumes:
- db:/var/lib/mysql
networks:
- backend
nginx:
image: nginx:1.21.6
container_name: nginx
restart: always
ports:
- 8000:80
networks:
- backend
volumes:
- ./:/var/www/html
- ./docker-compose/nginx:/etc/nginx/conf.d/
phpmyadmin:
image: phpmyadmin
container_name: pma
restart: always
ports:
- 8283:80
environment:
PMA_HOSTS: db
PMA_ARBITRARY: 1
PMA_USER: sqluser
PMA_PASSWORD: 2020
networks:
- backend
networks:
backend:
driver: bridge
volumes:
db:
Note:-
in Nginx service, I Created two shared volumes. The first one will synchronize contents from the current directory to /var/www inside the container. This way, when you make local changes to the application files, they will be quickly reflected in the application being served by Nginx inside the container (Which is not good for production). The second volume will make sure our Nginx configuration file, located at docker-compose/nginx/, is copied to the container’s Nginx configuration folder.
i tried to remove the first volume but keep the second one to use my custom configuration but it did not work at all why?

How to run laravel app using docker-compose?

Following is what I tried, is there something I doing wrong?
step1. create a simple laravel app at localhost.
composer create-project --prefer-dist laravel/laravel laravel-app 5.6
step2. create docker-compose.yml
version: '3'
services:
php:
image: php:7-fpm
ports:
- "3021:8000"
volumes:
- ./laravel-app:/app
composer:
image: composer:latest
volumes:
- ./laravel-app:/app
working_dir: /app
command: ["install","php artisan serve --host=0.0.0.0"]
depends_on:
- php
After that, I run docker-compose up --force-recreate -d and access 127.0.0.1:3021 at browser, but I get nothing.
Then I run docker-composer log, it shows me this error message:
Invalid argument php artisan serve --host=0.0.0.0. Use "composer require php artisan serve --host=0.0.0.0" instead to add packages to your composer.json.
How to fix this issue?
You are mixing commands. Composer does not "serve". Php has a build in dev server to "serve".
You can read more about it here: https://laravel.com/docs/4.2/quick
To actually get Laravel up and running please do the following:
1 - Run this in the laravel-app folder: composer install
2 - Create a Dockerfile with the following contents:
FROM php:7
RUN apt-get update -y && apt-get install -y libmcrypt-dev openssl
RUN docker-php-ext-install pdo mcrypt mbstring
RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer
WORKDIR /app
COPY . /app
CMD php artisan serve --host=0.0.0.0 --port=8000
EXPOSE 8000
3 - Build your docker image: docker build -t my-laravel-image .
4 - Finally replace the content of your docker-compose:
version: '3'
services:
web:
image: my-laravel-image
ports:
- 3021:8000
volumes:
- ./laravel-app:/app
A more complete tutorial can be found here (not mine): https://www.techiediaries.com/docker-compose-laravel/
EDIT:
in order to use the official compose image you could simply do this:
version: '3'
services:
composer:
image: composer:latest
working_dir: /app
entrypoint: php artisan serve --host=0.0.0.0
depends_on:
- php
volumes:
- ./laravel-app:/app
ports:
- "3021:8000"
Make sure ./laravel-app contains a laravel project. Otherwise this won't work!
in the main folder of your Laravel app, create a file named Dockerfile and insert this code:
FROM php:7
RUN apt-get update -y && apt-get install -y openssl zip unzip git
RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer
RUN docker-php-ext-install pdo pdo_mysql
WORKDIR /app
COPY . /app
RUN composer install
CMD php artisan serve --host=0.0.0.0 --port=8181
EXPOSE 8181
In the same main folder of Dockerfile, create a file named docker-compose.yml and insert this code:
version: '2'
services:
app:
build: .
ports:
- "8009:8000"
volumes:
- .:/app
env_file: .env
working_dir: /app
command: bash -c 'php artisan migrate && php artisan serve --host 0.0.0.0'
depends_on:
- db
links:
- db
db:
image: "mysql:5.7"
environment:
- MYSQL_ROOT_PASSWORD=yourpassword
- MYSQL_DATABASE=yourdbname
- MYSQL_USER=root
- MYSQL_PASSWORD=yourpassword
volumes:
- ./data/:/var/lib/mysql
ports:
- "3306:3306"
phpmyadmin:
depends_on:
- db
image: phpmyadmin/phpmyadmin
restart: always
ports:
- 8090:80
environment:
PMA_HOST: db
MYSQL_ROOT_PASSWORD: yourpassword
Open the terminal command line and go inside the laravel folder, and launch this commands:
docker.compose build
docker-compose up -d
if have need to create and migrate the db, or use other commands, launch the Laravel commands in this way:
docker-compose run app php artisan
The app will available at the address http://0.0.0.0:8009
Source: https://medium.com/#pierangelo1982/dockerize-an-existing-laravel-application-with-docker-compose-a45eb7956cbd

Can't access env variables in RUN script.sh Dockerfile

I have this Dockerfile:
FROM php:5.6-apache
WORKDIR /var/www/html/
# ENV VARIABLES
ENV INI_FOLDER /usr/local/etc/php
ENV WWW_FOLDER /var/www
# ADD THE ENV CONFIGURATOR AND SET PERMISSIONS
ADD env.sh $WWW_FOLDER/
RUN chmod +x $WWW_FOLDER/env.sh
RUN /var/www/env.sh
The problems is that in env.sh I don't have access to the variables set on the docker-compose. Is there any workaround to fix this?
UPDATE: added docker-compose
version: '2.0'
services:
app:
env_file:
- app/mysql.env
- app/app.env
volumes:
- C:\Users\svirl\Documents\workspace\docker\my-app:/var/www/html/:rw
build: app

Resources