I wish to install Symfony and use it on a project, but do it without installing it on my system. So I figured it could be done using Docker, yet my efforts to make it work haven't paid off so far.
I created a Dockerfile where I tried installing everything I could possibly need and then running Symfony, while I was setting up a simple docker-compose.yml. When I try to up it, the container just exists, and by its log, it seems that Symfony could not be found, even though the image seems to build ok.
So what would be the correct way to accomplish this?
Dockerfile:
FROM php:8.1-apache
RUN a2enmod rewrite
RUN apt-get update \
&& apt-get install -y libzip-dev git wget --no-install-recommends \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
RUN docker-php-ext-install pdo mysqli pdo_mysql zip;
RUN wget https://getcomposer.org/download/2.2.0/composer.phar \
&& mv composer.phar /usr/bin/composer && chmod +x /usr/bin/composer
RUN composer create-project symfony/skeleton:"6.1.*" app
RUN cd /app
CMD ["symfony", "server:start"]
docker-compose.yml:
version: '3.7'
services:
db:
image: mysql:5.7
environment:
- MYSQL_ROOT_PASSWORD=somerootpass
- MYSQL_PASSWORD=somepass
- MYSQL_DATABASE=dockerizeme_db
- MYSQL_USER=someuser
web:
build: .
ports:
- 8080:8000
volumes:
- './app:/app'
depends_on:
- db
You have a couple problems here.
First, you did not install the Symfony's CLI in your container, see https://symfony.com/download.
Without this, you can not use the symfony command. The compose create-project command does not install the CLI, it's only creating the framework skeleton.
Next, you are mounting a local folder ./app on your container's /app thus, the result of create project in your Dockerfile is overwritten at run time.
If you want to create the project in your local folder mounted inside the container, you would have to do it in the ENTRYPOINT.
But, since it's something you will most likely want to do only once, if you really do not want anything on your local computer, you could take the following approach.
Temporarily change your command, maybe in your docker-compose.yaml file to ["sleep", "infinity"] and re-up your containers
Run a command docker compose exec web composer create-project symfony/skeleton:"6.1.*" app
Change back your command and re-up your containers one last time
Bind mounts are mounted at run time so they are not yet mounted during your build.
Also, I see that you run Symfony's dev server but are using a Apache PHP image. I would normally do one or the other but not both.
Plus you do a RUN cd /app but the correct way to do that in that context would be WORKDIR /app
Related
Trying to run composer install during docker compose build from inside the php container, but it errors out at the end acting like the composer.json file isn't there. However if I comment out the last line in the Dockerfile (ie. RUN composer install), then do something like, docker exec -it <container name> bash, manually run composer install from inside the container where /var/www/html/composer.json does in fact exist it works.
Dockerfile
FROM php:7.4-apache
COPY --from=composer /usr/bin/composer /usr/bin/composer
RUN docker-php-ext-install pdo_mysql mysqli
RUN a2enmod rewrite
WORKDIR /var/www/html
## install and run composer so that this test is self contained
RUN apt-get update
RUN apt-get install -y git
RUN composer install
Produces the following
=> ERROR [stage-0 8/8] RUN composer install 0.5s
------
> [stage-0 8/8] RUN composer install:
#0 0.437 Do not run Composer as root/super user! See https://getcomposer.org/root for details
#0 0.446 Composer could not find a composer.json file in /var/www/html
#0 0.446 To initialize a project, please create a composer.json file. See https://getcomposer.org/basic-usage
------
failed to solve: executor failed running [/bin/sh -c composer install]: exit code: 1
In case it's important this is the docker-compose.yml file
version: "3.9"
services:
php:
build: ./docker/php
volumes:
- ./src:/var/www/html
ports:
- 8080:80
restart: unless-stopped
mysql:
image: mariadb
volumes:
- ./docker/sql:/docker-entrypoint-initdb.d/
ports:
- 3306:3306
environment:
MARIADB_ROOT_PASSWORD: xxx
MARIADB_DATABASE: xxx
MARIADB_USER: xxx
MARIADB_PASSWORD: xxx
restart: unless-stopped
You're already pretty close with your container build directives, it's just that I'd say you only need the composer.json during the build and you actually need to have the vendor folder in the service container afterwards.
It's bascially two commands:
First update the build instructions:
<<'DOCKERFILE' tee Dockerfile >/dev/null && git add Dockerfile && git commit -m 'add composer install to build'
ARG ver=7.4
FROM php:$ver-cli
COPY --from=composer /usr/bin/composer /usr/bin/composer
COPY composer.json composer.json
RUN set -ex ; \
apt-get update ; \
apt-get install -y git zip ; \
composer -n validate --strict ; \
composer -n install --no-scripts --ignore-platform-reqs --no-dev
ARG ver=7.4
FROM php:$ver-apache
RUN set -ex ; \
docker-php-ext-install pdo_mysql mysqli ; \
a2enmod rewrite
COPY --from=0 vendor vendor
DOCKERFILE
Then build the container (this time with the composer.json file):
git archive --format tar HEAD Dockerfile composer.json | docker build --no-cache --rm --force-rm --tag my:build -
You'll see it run through. And given the composer.json file actually exists for the build context, then validates within the build container and you don't have any networking issues this should do it. You have not shared your build context properties, so this is the bare minimum for composer in docker (Dockerfile + composer.json).
Mind the PHP version in use, you find it parameterized so that the version can be controlled. Time to step away from PHP 7.4 which is going EOL soon. Docker Compose supports build parameters so you can do that in different working trees.
And here the takeaway: If you want more files from context, add them to the context and remember that when you need to copy from the context into the container again, there must be no --from option, that is only to copy from other containers (either intermediate stages or from the container repository). You can control all that with the Dockerfile as you had it already and additionally shown again above.
I am trying to install Laravel inside a php container using this line on my Dockerfile:
RUN composer create-project laravel/laravel=8.* . --prefer-dist
My goal is to install it on my container directory /var/www/html. My first assumption is that by using . , the command ran on the current working directory, which is /var/www/html itself. And actually, it works when I go inside the container and run the command there. But, when building using the Dockerfile, seems that it doesn't install anything anywhere. On the contrary, the message I got on the terminal looked like the command ran successfully:
=> [stage-0 6/6] RUN composer create-project laravel/laravel=8.* . --prefer-dist
Currently my docker-compose.yaml looked like this:
version: '3.8'
services:
# PHP + Apache Service
php-apache:
build:
context: ./php-apache
working_dir: /var/www/html
ports:
- 80:80
volumes:
- ./src/:/var/www/html
- ./php-apache/apache2.conf:/etc/apache2/apache2.conf
- ./php-apache/000-default.conf:/etc/apache2/sites-available/000-default.conf
depends_on:
mysql:
condition: service_healthy
# other services and volumes...
Also my Dockerfile:
FROM php:8.1-apache
# Mysql driver on php
RUN docker-php-ext-install pdo pdo_mysql mysqli
# Composer
RUN apt-get update && apt-get install -y git zip
COPY --from=composer:2.2.2 /usr/bin/composer /usr/bin/composer
# Node.js
RUN apt-get update && apt-get install -y nodejs npm
# Laravel
RUN composer create-project laravel/laravel=8.* . --prefer-dist
I already set the working_dir to /var/www/html. Why is that the case here?
You could use the entry point script to run scripts after the container has started.
Create a bash script in the same location where you have Dockerfile.
start-container.sh
#!/usr/bin/env bash
#This will try to install laravel in /var/www/html/new-laravel if folder does not exists
composer create-project laravel/laravel=8.* /var/www/html/new-laravel --prefer-dist
#If your container gets exited, then consider restarting apache, here is an #example
#service php7.4-fpm start && nginx -g "daemon off;"
Remember to make the bash script executable, run the command before you run docker-compose build
chmod u+x start-container.sh
Then in your Dockerfile towards the end add:
ENTRYPOINT ["start-container"]
Then:
docker-compose stop && docker-compose build && docker-compose up -d
I am trying to run a webserver container with nginx and a php-fpm server running a Laravel application. The directory houses a frontend and backend directory so my paths are not off in the configuration files.
I setup a docker-compose.yml file
version: '2'
services:
webserver:
build:
context: ./
dockerfile: webserver.docker
volumes:
- /home/colesam/Documents/code/todo/backend:/var/www
ports:
- "8080:80"
links:
- backend
backend:
build:
context: ./
dockerfile: backend.docker
volumes:
- ./home/colesam/Documents/code/todo/backend:/var/www
And php-fpm Dockerfile (backend.docker)
FROM php:7.2-fpm
RUN apt-get update -y && apt-get install -y libmcrypt-dev openssl
RUN pecl install mcrypt-1.0.2
RUN docker-php-ext-enable mcrypt
RUN docker-php-ext-install pdo mbstring
RUN apt-get install -y apt-transport-https
RUN apt-get install -y curl
RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer
RUN chown -R www-data:www-data /var/www
VOLUME ["/var/www"]
RUN ls -al /var/www
WORKDIR /var/www
RUN composer install
And the nginx webserver Dockerfile (webserver.docker)
FROM nginx:1.10
ADD ./vhost.conf /etc/nginx/conf.d/default.conf
WORKDIR /var/www
For some reason when I run docker-compose up -d --build I always fail at this step of the build process:
Step 13/13 : RUN composer install
---> Running in 65bb97f03004
Do not run Composer as root/super user! See https://getcomposer.org/root for details
Composer could not find a composer.json file in /var/www
To initialize a project, please create a composer.json file as described in the https://getcomposer.org/ "Getting Started" section
ERROR: Service 'backend' failed to build: The command '/bin/sh -c composer install' returned a non-zero code: 1
From the last line of the output it looks like it failed because /var/www/was empty and didn't have the files copied over like composer.json. I looked around a lot and this stackoverflow issue seemed to be the most related to what was happening but I think I'm already following everything the accepted answer suggests.
Do I need to include a COPY or ADD command even though I'm mounting the folder through a volume?
The build phase does not see any mounted volumes. The only thing that is available to "build" are the things defined in the backend.docker and in the compose section of build:
build:
context: ./
dockerfile: backend.docker
Do I need to include a COPY or ADD command even though I'm mounting the folder through a volume?
Yes, modify your backend.docker similar to this
...
WORKDIR /var/www
ADD composer.json .
RUN composer install
I'll preface this by saying I am very new to the docker world and despite reading documentation I am still a little confused about a few things.
I want to build a container with centos7 apache and php. I don't want to use an already existing image, want to build a custom container. I have the following folder structure
My rw/docker/webserver/Dockerfile:
FROM centos:7
ENV container docker
RUN (cd /lib/systemd/system/sysinit.target.wants/; for i in *; do [ $i == \
systemd-tmpfiles-setup.service ] || rm -f $i; done); \
rm -f /lib/systemd/system/multi-user.target.wants/*;\
rm -f /etc/systemd/system/*.wants/*;\
rm -f /lib/systemd/system/local-fs.target.wants/*; \
rm -f /lib/systemd/system/sockets.target.wants/*udev*; \
rm -f /lib/systemd/system/sockets.target.wants/*initctl*; \
rm -f /lib/systemd/system/basic.target.wants/*;\
rm -f /lib/systemd/system/anaconda.target.wants/*;
VOLUME [ "/sys/fs/cgroup" ]
CMD ["/usr/sbin/init"]
RUN yum -y install httpd
RUN systemctl start httpd
RUN systemctl enable httpd
RUN yum update -y && yum install -y libpng-dev curl libcurl4-openssl-dev
RUN docker-php-ext-install pdo pdo_mysql gd curl
RUN a2enmod rewrite
MY docker-compose.yml
version: '2'
services:
webserver:
build: ./docker/webserver
ports:
- "80:80"
- "443:443"
volumes:
- /**PATH**/rw/services:/var/www/html
links:
- db
db:
image: mysql:5.7
ports:
- "3306:3306"
volumes:
- ./db:/var/lib/mysql
environment:
- MYSQL_ROOT_PASSWORD=****
- MYSQL_DATABASE=****
This fails when docker tries to start httpd with the error
ERROR: Service 'webserver' failed to build: The command '/bin/sh -c systemctl start httpd' returned a non-zero code: 1
Q1. Why is the install failing?
Q2. Is the the proper way to do this? Should my dockerfile for centos and apache+php be separate. If yes, how does that work?
Q1. I think systemctl may not be provided with CentOS docker image.
Indeed, docker services are not meant to be run as daemons, but in the foreground. Take a look at apache's original http-foreground shell script for a better understanding of the concept.
Q2. Not that's not the right way IMHO.
Running apache is the job of an entrypoint or command script.
So instead of RUN your-command-to-run-apache, it would rather be CMD your-command-to-run-apache.
Once again, Apache official repository can give you some clue about this.
To my eyes these kinds of Dockerfiles look too old as they try to map the external docker daemon inside the container. That's a workaround as a systemd daemon cannot be run separately in a container.
Instead I am using the docker-systemctl-replacement script. The docker systemctl.py can parse the normal *.service files to know how to start and stop services. You can register it as the CMD of an image in which case it will look for all the systemctl-enabled services - those will be started and stopped in the correct order.
There are even some testcases for the LAMP stack available, so it should work in your case quite smoothly. The systemctl.py script is compatible with the systemd systemctl as much as that one simply overwrite the /usr/bin/systemctl inside the image - and all the non-docker installation instructions will work for docker builds.
Let's say I have the following situation:
docker-compose.yml
version: '3'
services:
web:
build: .
links:
- apache
- php
- node
depends_on:
- apache
- php
- node
volumes:
- .:/var/www/html
apache:
image: httpd
php:
image: php
node:
image: node
and I also have a Dockerfile
FROM phusion/baseimage
RUN apt-get update
RUN apt-get install -yq git curl zip wget curl
RUN curl -s https://getcomposer.org/installer | php # error, no PHP exec found
RUN mv composer.phar /usr/local/bin/composer
RUN npm install -g bower gulp
COPY ./ /var/www/html
WORKDIR /var/www/html
RUN apt-get clean
RUN rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
CMD ["/sbin/my_init"]
Now my question is: how could I use PHP & Node, which are installed in separate containers, in this main app Dockerfile? Is that even possible, or do I need to manually install PHP & Node inside my Dockerfile?
Docker doesn't work the way you are thinking. This isn't like code inheritance or configuring a single machine with multiple runtime languages. You are configuring multiple virtual machines, each with their own runtime environment.
if you want to run a PHP app, you put that app in the container that has PHP. same with Node.