Docker-compose and composer for laravel project - docker

I'm trying to use docker ( first time at all ) to build a development env for my laravel projects.
I have read the documentation and looks like that docker-compose.yml file is the way to go, at least in my case.
I'm trying to create a LEMP env and this is my compose file:
version: "3.1"
services:
memcached:
image: memcached:alpine
container_name: 01dev-memcached
mysql:
image: mysql:8.0
container_name: 01dev-mysql
working_dir: /application
volumes:
- ./:/application
environment:
- MYSQL_ROOT_PASSWORD=laravel
- MYSQL_DATABASE=laravel
- MYSQL_USER=laravel
- MYSQL_PASSWORD=laravel
ports:
- "8082:3306"
webserver:
image: nginx:alpine
container_name: 01dev-webserver
working_dir: /application
volumes:
- ./:/application
- ./phpdocker/nginx/nginx.conf:/etc/nginx/conf.d/default.conf
ports:
- "8080:80"
php-fpm:
build: phpdocker/php-fpm
container_name: 01dev-php-fpm
working_dir: /application
volumes:
- ./:/application
- ./phpdocker/php-fpm/php-ini-overrides.ini:/etc/php/7.3/fpm/conf.d/99-overrides.ini
My nginx.conf file:
server {
listen 80 default;
client_max_body_size 108M;
access_log /var/log/nginx/application.access.log;
root /application/public;
index index.php;
if (!-e $request_filename) {
rewrite ^.*$ /index.php last;
}
location ~ \.php$ {
fastcgi_pass php-fpm:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PHP_VALUE "error_log=/var/log/nginx/application_php_errors.log";
fastcgi_buffers 16 16k;
fastcgi_buffer_size 32k;
include fastcgi_params;
}
}
since is a Laravel application I need to set the public folder as root, so in my nginx.conf I have set it.
If I manually create the public folder with a index.php with just a echo "hello"; I'm able to connect and see the string on http://localhost:8080.
Now I need to use composer to install and to manage my project so I found a composer image and I have added it under services in docker-compose.yml:
composer:
restart: 'no'
container_name: 01dev-composer
image: "composer"
command: install
volumes:
- ./:/application
As far as I know with volumes I bind my host to the container path, so it should point outside the public folder, am I right?
If I run docker-compose up I see that the composer container exit with code 1:
01dev-composer | Composer could not find a composer.json file in /app
01dev-composer | To initialize a project, please create a composer.json file as described in the https://getcomposer.org/ "Getting Started" section
01dev-composer exited with code 1
And I'm not able to connect to it:
docker-compose exec composer install
ERROR: No container found for composer_1
How can I use composer in my project? There is a better way to do that?

See composer Dockerfile:
WORKDIR /app
This image's working dir is /app, and also from the guide, all example mount code directory to the /app folder in container.
Besides, the error also tells you that:
Composer could not find a composer.json file in /app
So, the thing you need to do is mount your code directory to /app & make sure this service start first, then it will generate vendor folder in your source code directory:
volumes:
- ./:/app

Related

Docker + nginx + slim

I'm a new user of Docker. What I want to do is to setup (on my Windows PC) the Docker platform with a nginx server and a slim framework on this server, so that I be able to "host" a simple "hello world" page.
My question is: should I create a container containing the Nginx and inside that container install the Slim framework?
Or should i create two different containers (one for Nginx, one for Slim). And if so, how those two communicate?
Anyway whatever the solution is, first I would like to understand the "architecture" of this "build" and after that how to do it.
Thanks in advance
You can use two containers, using docker-compose to connect slim and nginx, something like this:
docker-compose.yaml
version: "3.8"
services:
php:
container_name: slim
build:
context: ./docker/php
ports:
- '9000:9000'
volumes:
- .:/var/www/slim_app
nginx:
container_name: nginx
image: nginx:stable-alpine
ports:
- '80:80'
volumes:
- .:/var/www/slim_app
- ./docker/nginx/default.conf:/etc/nginx/conf.d/default.conf
depends_on:
- php
DOCKERFILE in ./docker/php
FROM php:7.4-fpm
RUN docker-php-ext-install ALL_YOUR EXTENSIONS
WORKDIR /var/www/slim_app
RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer
Docker nginx in /docker/nginx/default.conf
server {
listen 80;
index index.php;
server_name localhost;
root /var/www/slim_app/public;
location / {
try_files $uri /index.php$is_args$args;
}
location ~ ^/index\\.php(/|$) {
fastcgi_pass php:9000;
fastcgi_split_path_info ^(.+\\.php)(/.*)$;
internal;
}
location ~ \\.php$ {
return 404;
}
}
Just execute the containers
docker-compose up -d
go to http://localhost/

Docker Compose with NGINX proxy pass thru not working

Following is my Docker Compose file & NGINX conf file.
The application seems to work and NGINX is also up, but the proxy_pass setting doesn't seem to work properly.
File
docker-compose.yaml
networks:
webapp:
services:
web:
image: nginx
volumes:
- ./data/ntemplates:/etc/nginx/templates
- ./webapp.conf:/etc/nginx/conf.d/webapp.conf
ports:
- "8080:80"
networks:
- webapp
pyweb:
build: .
ports:
- "5000:5000"
networks:
- webapp
redis:
image: "redis:alpine"
networks:
- webapp
File webapp.conf
server {
listen 80;
listen [::]:80;
server_name localhost;
location / {
proxy_pass "http://pyweb_1:5000/";
}
#error_page 404 /404.html;
error_page 500 502 503 504 /50x.html;
}
Service pyweb is working if properly if directly accessed by http://pyweb_1:5000
I created this app based on docker getting started page
For completeness below are other files and seems to be working just fine.
File Dockerfile
FROM python:3.7-alpine
WORKDIR /code
ENV FLASK_APP=app.py
ENV FLASK_RUN_HOST=0.0.0.0
RUN apk add --no-cache gcc musl-dev linux-headers
COPY requirements.txt requirements.txt
RUN pip install -r requirements.txt
EXPOSE 5000
COPY . .
CMD ["flask", "run"]FROM python:3.7-alpine
WORKDIR /code
ENV FLASK_APP=app.py
ENV FLASK_RUN_HOST=0.0.0.0
RUN apk add --no-cache gcc musl-dev linux-headers
COPY requirements.txt requirements.txt
RUN pip install -r requirements.txt
EXPOSE 5000
COPY . .
CMD ["flask", "run"]
File requirement.txt
flask
redis
File app.py
import time
import redis
from flask import Flask
app = Flask(__name__)
cache = redis.Redis(host='redis', port=6379)
def get_hit_count():
retries = 5
while True:
try:
return cache.incr('hits')
except redis.exceptions.ConnectionError as exc:
if retries == 0:
raise exc
retries -= 1
time.sleep(0.5)
#app.route('/')
def hello():
count = get_hit_count()
return 'Hello World! I have been seen {} times.\n'.format(count)
EDIT:
You're currently not using the nginx configuration. I didn't read carefully your docker-compose file. You can fix it by mapping the webapp.conf on /etc/nginx/conf.d/default.conf. e.g.
services:
web:
image: nginx
volumes:
- ./data/ntemplates:/etc/nginx/templates
- ./webapp.conf:/etc/nginx/conf.d/default.conf
ports:
- "8080:80"
depends_on:
- pyweb
networks:
- webapp
There are 2 issues:
you don't know what container name will be used by docker-compose
you don't know the order used to start the containers
docker-compose allows you to solve the first issue in 2 ways:
define a container_name subsection
use the service name
This means that you can simply use proxy_pass "http://pyweb:5000/"; in your nginx setup
The second issue can be fixed by adding a depends_on subsection in the nginx service. e.g.
services:
web:
image: nginx
volumes:
- ./data/ntemplates:/etc/nginx/templates
- ./webapp.conf:/etc/nginx/conf.d/webapp.conf
depends_on:
- pyweb
ports:
- "8080:80"
networks:
- webapp
Nevertheless, the depends_on might not be enough since it does not check the service status but it only make sure that the docker service is started (as stated in the documentation).
You'll need to find another way to monitor if the service is actually started.

Sharing volumes in networked docker containers with docker composer fails

I have two docker-compose.yml files
THe first one is a global one and am using it to configure nginx webserver and the other one am using it for holding the application code and below are their configurations
First one with nginx configuration
version: '3'
services:
app:
build:
context: .
dockerfile: Dockerfile
image: globaldocker
container_name: app
restart: unless-stopped
tty: true
working_dir: /var/www
volumes:
- ./:/var/www
- ./dockerconfig/php/local.ini:/usr/local/etc/php/conf.d/local.ini
networks:
- common_network
webserver:
image: nginx
container_name: webserver
restart: unless-stopped
tty: true
ports:
- "80:80"
- "443:443"
volumes:
- ./:/var/www
- ./dockerconfig/nginx/:/etc/nginx/conf.d/
networks:
- webserver_network
- common_network
networks:
common_network:
external: false
webserver_network:
external: false
The above creates two networks
global_docker_common_network, global_docker_webserver_network
On the docker config folder there is a nginx configuration like
server {
listen 80;
server_name pos.test www.pos.test;
index index.php index.html;
//other nginx configurations for pos.test
}
ON THE docker-compose configuration with php file
Now the one one holding the source code for pos.test i have the following configuration
app:
build:
context: .
dockerfile: Dockerfile
image: posapp/php
container_name: envanto_pos
restart: unless-stopped
tty: true
working_dir: /var/www/pos
volumes:
- ./:/var/www/pos
- ./dockerconfig/nginx/:/etc/nginx/conf.d/
networks:
- globaldocker_webserver_network
networks:
globaldocker_webserver_network:
external: true
Which i have added the external network
When i try accessing nginx pos.test it doesnt display the application but only shows the default nginx page
I have tried accessing the first docker nginx configuration bash and checked on the var/www/pos folder but i cant see the files from the second docker config(source code).
How do i share volumes with my nginx docker configuration container so that when i access docker via exposed port 80 am able to access my site pos.test
What am i missing out on this to make this work?
UPDATE
The two docker configuration files are located on different folders on my host machine
UPDATE ON THE QUESTION
This is my nginx config file
server {
listen 80;
server_name pos.test www.pos.test;
index index.php index.html;
error_log /var/log/nginx/pos_error.log;
access_log /var/log/nginx/pos_access.log;
root /var/www/pos/web;
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;
}
}
you are mounting the current directory of docker-compose file each. So the only that container will have the source code which resides in the same source code directory.
You need some common directory
First File
volumes:
- /path_to_sc/common:/var/www
Second File
volumes:
- /path_to_sc/common:/var/www/pos
When I try accessing Nginx pos.test it doesn't display the application
but only shows the default Nginx page
Probably you first File not picking correct configuration. Double-check ./dockerconfig/nginx/:/etc/nginx/conf.d/ or run the command inside docker to verify the correct configuration file.
docker exec nginx bash -c "cat /etc/nginx/conf.d/filename.conf`
I have tried accessing the first docker nginx configuration bash and
checked on the var/www/pos folder but i cant see the files from the
second docker config(source code).
Mount the common directory so that can accessible for both containers.
update:
From your comment, it seems like there is a syntax error in your docker-compose file. Take a look into this example
web:
image: nginx
volumes:
- ./data:/var/www/html/
ports:
- 80:80
command: [nginx-debug, '-g', 'daemon off;']
web2:
image: nginx
volumes:
- ./data:/var/www/html
command: [nginx-debug, '-g', 'daemon off;']

Linking two docker compose configuration fails with a bridge network

I have setup a global docker configuration which i expect to handle nginx,and database configuration. This has the following configuration
webserver:
image: nginx
container_name: webserver
restart: unless-stopped
tty: true
ports:
- "80:80"
- "443:443"
volumes:
- ./:/var/www
- ./dockerconfig/nginx/conf.d/:/etc/nginx/conf.d/
networks:
- common
networks:
common:
driver: bridge
on the folder dockerconfig/nginx/conf.d i have a file pos.test with the following nginx config
server {
listen 80;
server_name pos.test www.pos.test;
index index.php index.html;
error_log /var/log/nginx/error.log;
access_log /var/log/nginx/access.log;
root /var/www/web;
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;
}
}
ON THE SECOND DOCKER configuration file i have
Now i have another docker configuration with the following
app:
build:
context: .
dockerfile: Dockerfile
image: posapp/php
container_name: envanto_pos
restart: unless-stopped
tty: true
working_dir: /var/www/pos
volumes:
- ./:/var/www/pos
networks:
- common
networks:
common:
driver: bridge
Now after running both docker files via docker-compose up -d they both run without any issue but now i nginx cannot run the domain pos.test where the app code is executed on the second docker file
The idea behind this is to have one docker-compose configuration file handle nginx server while the other configuration to copy files is handled by the other docker configuration files
How can i make both docker configurations work as including the network part with a bridge fails to work.What am i missing out.
UPDATE
I know one of the way to solve this would be to add a single docker config file but i want to split the docker config files to different configuration files
You are most likely running the docker-compose command from different directories, and not overriding the compose project name. Docker compose will prefix objects created, like containers, volumes, and networks, with the project name, to allow different instances to be run in isolation from each other.
To solve this, you need a known name of the network, and you'll want to define it as external to at least one of your compose files. When the network is defined as external, compose will not try to create it, but will require that it was already created externally, either by a docker network create command or by the other compose file.
To create the network with a known name, you can specify the name value in newer versions of the docker compose file.
Here is the first compose file that would create the network with a known name:
version: '3.7'
services:
webserver:
image: nginx
container_name: webserver
restart: unless-stopped
tty: true
ports:
- "80:80"
- "443:443"
volumes:
- ./:/var/www
- ./dockerconfig/nginx/conf.d/:/etc/nginx/conf.d/
networks:
- common
networks:
common:
external: false
name: common
And the second compose file that would use the already created network:
version: '3.7'
services:
app:
build:
context: .
dockerfile: Dockerfile
image: posapp/php
container_name: envanto_pos
restart: unless-stopped
tty: true
working_dir: /var/www/pos
volumes:
- ./:/var/www/pos
networks:
- common
networks:
common:
external: true
name: common
The problem is that you're redefining the common network.
You can define the 2 docker-compose.yml files as follow:
docker-compose.yml
networks:
common:
driver: bridge
services:
app:
build:
context: .
dockerfile: Dockerfile
image: posapp/php
container_name: envanto_pos
restart: unless-stopped
tty: true
working_dir: /var/www/pos
volumes:
- ./${AppPath}/:/var/www/pos
networks:
- common
and docker-compose.webserver.yml
services:
webserver:
image: nginx
container_name: webserver
restart: unless-stopped
tty: true
ports:
- "80:80"
- "443:443"
volumes:
- ./${WebserverPath}/:/var/www
- ./${WebserverPath}/dockerconfig/nginx/conf.d/:/etc/nginx/conf.d/
networks:
- common
and start the application with:
docker-compose -f docker-compose.yml -f docker-compose.webserver.yml up -d

Docker compose with nginx keeps displaying welcome page

I'm new to docker and trying the simplest docker-compose.yml showing an hello world page to build on top of that with eventually a full LEMP stack that would have the same config as my server. However most tutorials are obsolete and there are so many ways of using docker that I can't find one using only Docker compose v3 that is still actual. I checked the docs and it's awfully confusing as well for a beginner, been trying to make it work for the past 5 hours so I thought I'd ask on SO.
docker-compose.yml
version: '3'
services:
web:
image: bitnami/nginx:1.10.3-r0 #using this version as it's the same on my server
volumes:
- "./test.conf:/etc/nginx/sites-available/test.local"
- "./test.conf:/etc/nginx/sites-enabled/test.local"
- "./code:/var/www/html" #code contains only a basic index.html file
ports:
- "80:80"
test.conf
server {
listen 80;
listen [::]:80;
server_name test.local;
index index.html; #Only a basic helloworld index.html file
error_log /var/log/nginx/error.log;
access_log /var/log/nginx/access.log;
root /var/www/html;
}
Do I need a Dockerfile with this? Tutorials don't seem to mention it's needed.
NOTE:
Tried adding the volume
- "./default.conf:/etc/nginx/conf.d/default.conf"
but nothing changes and the welcome page still loads, while with nginx:latest I get a very verbose error containing this phrase: "unknown: Are you trying to mount a directory onto a file (or vice-versa)? Check if the specified host path exists and is the expected type".
UPDATE about docker-compose.yml:
Without the line "./code:/usr/share/nginx/html", the /usr/share/nginx/html folder contains the default index.html file (expected)
With the line "./code:/usr/share/nginx/html", the /usr/share/nginx/html folder is EMPTY!
With the line "./:/usr/share/nginx/html", the /usr/share/nginx/html folder has and empty "code" folder and a bunch of random test files I deleted a while ago.
Between tries, I run my reset script to make sure I start fresh:
docker rm $(docker ps -a -q)
docker rmi $(docker images -q) --force
docker volume rm $(docker volume ls -q)
Running docker inspect <container> returns this for the volume, not sure it's normal that the type is "bind" for as a bind mount instead of a volume.
"Mounts": [
{
"Type": "bind",
"Source": "/e/DEV/sandbox/docker",
"Destination": "/usr/share/nginx/html",
"Mode": "rw",
"RW": true,
"Propagation": "rprivate"
}
],
It's easy to mount your own hello world page. I'll explain it using the official nginx:latest image but you can do it for yourself with the bitnami image if you want.
First the very basic. Just run the nginx container (without docker-compose). I'll explain it in detail and basic, of course I can try to perform more advanced or faster commands to read files which are inside the container but this can be confusing for a beginner. So just run the container and name it my-nginx:
$ docker run --rm -d -p 80:80 --name my-nginx nginx
Go to localhost:80, you'll see the default nginx page.
Now you can exec inside the container by using it's name. exec will bring you 'inside the container' so you can check its files.
$ docker exec -it my-nginx bash
root#2888fdb672a1:/# cd /etc/nginx/
root#2888fdb672a1:/etc/nginx# ls
conf.d koi-utf mime.types nginx.conf uwsgi_params
fastcgi_params koi-win modules scgi_params win-utf
Now read the nginx.conf by using cat.
The most important line in this file is:
include /etc/nginx/conf.d/*.conf;
This means all the confs inside that directory are used/read.
So go into /etc/nginx/conf.d/.
root#2888fdb672a1:~# cd /etc/nginx/conf.d/
root#2888fdb672a1:/etc/nginx/conf.d# ls
default.conf
The default.conf is the only file. Inside this file you see the configuration:
listen 80;
server_name localhost;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
}
server is local host, port is 80 and the file that will be displayed is in the directory /usr/share/nginx/html/
Now check that file in your container:
root#2888fdb672a1:/etc/nginx/conf.d# cat /usr/share/nginx/html/index.html
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
body {
width: 35em;
margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif;
}
</style>
...
It's the expected file. It's the 'Welcome to Nginx' page we can see.
So how can we show our own index.html? By just mounting it in /usr/share/nginx/html.
You'll docker-compose.yaml will look like this.
version: '3'
services:
web:
image: nginx:latest
volumes:
- ./code:/usr/share/nginx/html
ports:
- "80:80"
The code directory just contains an index.html with hello world.
Run docker-compose up -d --build and when you curl localhost:80 you will see your own index.html.
If you really want to put your code in /var/www/html instead of /usr/share/nginx you can do that.
Use your test.conf. Here you define to put your file in /var/www/html/:
server {
listen 80;
listen [::]:80;
server_name test.local;
index index.html; #Only a basic helloworld index.html file
error_log /var/log/nginx/error.log;
access_log /var/log/nginx/access.log;
root /var/www/html;
}
In the compose you will overwrite the default.conf with your own conf where you tell nginx to look in /var/www/html.
Your compose can look like this:
version: '3'
services:
web:
image: nginx:latest
volumes:
- "./test.conf:/etc/nginx/conf.d/default.conf"
- "./code:/var/www/html"
ports:
- "80:80"
Now you will also see your own index.html while it's on your own specified location. Long answer but I hope this helps.
After struggling a lot on this question, I have figured out three factors that made my deploy with docker-compose work.
I did a website in nodejs.
We expose web part and nginx on port 80
Dockerfile for nodejs : [ important line is -> EXPOSE 80 ]
FROM node:14-alpine
WORKDIR /
COPY package.json ./
EXPOSE 80
RUN npm install
COPY . .
CMD ["node", "bin/www"]
Nginx.conf for nginx : [ important line is -> listen 80; ]
events {
}
http {
server {
listen 80;
location / {
proxy_pass http://nodejs:3000;
}
}
}
We give to nginx config file, the name and port of web's image
docker-compose.yaml :
[ important line is -> image: nodejs ] that is the name of web's image
AND
[ important line is -> ports: -"3000:3000" ] that is the port to run web's part
version: "3.7"
services:
nodejs:
build:
context: .
dockerfile: Dockerfile
image: nodejs
container_name: nodejs
restart: unless-stopped
networks:
- app-network
ports:
- "3000:3000"
webserver:
image: nginx
container_name: webserver
restart: unless-stopped
ports:
- "80:80"
volumes:
- ./nginx/nginx.conf:/etc/nginx/nginx.conf
- ./nginx/:/etc/nginx/conf.d
depends_on:
- nodejs
networks:
- app-network
networks:
app-network:
driver: bridge
Nginx.conf for nginx : [ important line is -> proxy_pass http://nodejs:3000; ]
events {
}
http {
server {
listen 80;
location / {
proxy_pass http://nodejs:3000;
}
}
}
We give nginx's image, volumes as path for the config file to replace default one
Tree :
mainfolder
.
|_____nginx
| |______nginx.conf
|
|_____Dockerfile
|
|_____docker-compose.yaml
docker-compose.yaml :
[ important line is -> ./nginx/nginx.conf:/etc/nginx/nginx.conf ] to replace config file
version: "3.7"
services:
nodejs:
build:
context: .
dockerfile: Dockerfile
image: nodejs
container_name: nodejs
restart: unless-stopped
networks:
- app-network
ports:
- "3000:3000"
webserver:
image: nginx
container_name: webserver
restart: unless-stopped
ports:
- "80:80"
volumes:
- ./nginx/nginx.conf:/etc/nginx/nginx.conf
depends_on:
- nodejs
networks:
- app-network
networks:
app-network:
driver: bridge

Resources