In my first attempt at running a more complex application through Docker, I selected the Symfony Demo app and assembled a docker build structure to accommodate it.
The first image is httpd: it runs as root (dropping to www-data afterwards) and talks through the 'server' custom network.
The second image is php (fpm): it runs as root (dropping to www-data afterwards) and also talks through the 'server' custom network.
The third image is composer: it runs as UID and GID 1000. Its entrypoint command is composer create-project symfony/symfony-demo symfony-demo
All containers share the same bind mount, where the symfony-demo app is located.
Then I go to localhost:8080 in the browser just to end up with a Symfony error:
The stream or file "/usr/local/apache2/htdocs/symfony-demo/var/log/dev.log" could not be opened: failed to open stream: Permission denied
The thing is... this file mentioned doesn't even exist at /var/log/. That folder is empty.
All files in the bind mount have permissions 1000:1000 (my user UID/GID) and are configured like this: -rw-r--r--.
I've tried running httpd and php as: UID 33 (www-data) and GID 33; UID 0 (root) and GID 33 (and vice-versa); and also as 1000:1000 or 1000:33, but all these combinations (when they successfully get httpd/php to start up) result in the same error.
docker-compose.yml:
version: "3"
services:
httpd:
build: "./httpd/"
container_name: "webserver"
depends_on:
- php
ports:
- "8080:80"
networks:
- server
volumes:
- ../app:/usr/local/apache2/htdocs/
php:
build: "./php/"
depends_on:
- composer
container_name: "php"
networks:
- server
volumes:
- ../app:/usr/local/apache2/htdocs/
composer:
build: "./composer/"
container_name: "composer"
user: "1000:1000"
volumes:
- ../app:/usr/local/apache2/htdocs/
networks:
server:
driver: bridge
composer Dockerfile:
FROM composer:1.8
WORKDIR /usr/local/apache2/htdocs/
CMD ["composer", "create-project", "symfony/symfony-demo", "symfony-demo"]
httpd Dockerfile:
FROM httpd:2.4
COPY ./config/httpd.conf /usr/local/apache2/conf/httpd.conf
COPY ./config/httpd-vhosts.conf /usr/local/apache2/conf/extra/httpd-vhosts.conf
COPY ./config/php-fpm.conf /usr/local/apache2/conf/extra/php-fpm.conf
WORKDIR /usr/local/apache2/htdocs
php Dockerfile:
FROM php:7.3-fpm
RUN cp "$PHP_INI_DIR/php.ini-development" "$PHP_INI_DIR/php.ini"
COPY ./config/timezone.ini $PHP_INI_DIR/conf.d/
COPY ./config/www.conf /usr/local/etc/php-fpm.d/www.conf
RUN apt-get update && \
apt-get install -y libicu-dev
RUN docker-php-ext-install intl
WORKDIR /usr/local/apache2/htdocs
just give the write permission
chmod -R 777 /usr/local/apache2/htdocs/symfony-demo/var/log/dev.log
here symfony doc for file permission: https://symfony.com/doc/current/setup/file_permissions.html
On second thoughts: my previous solution (as is) doesn't work in RHEL/Fedora/CentOS, because www-data does not exist there by default, causing Docker to fail to start.
My new solution - distro agnostic
For simplicity, I've decided to simply write composer's entrypoint script to set -rw-rw---- permissions at /app. That way, I can run composer as user 1000 and the same group PHP runs as (a new user and group was created just for that). Now PHP can write to SQLite3 database files inside the project and composer writes as user 1000, which I can edit.
It's basically what #habibun said, but I only need to give group write permissions, not full write permissions.
Be aware that SELinux will deny composer write access to your bind mount. You must configure SELinux to allow this operation.
This is my repository where this project is stored, if you're looking for a reference: https://github.com/o-alquimista/symfony-demo-docker/
User namespace solution - works fine for Debian/Ubuntu hosts
Composer should write to /app as user 33 (www-data), and so should php and httpd after they drop privileges. I was able to keep present permission settings (only owner can write) by making use of user namespaces. The user www-data is now mapped to the range 967 and beyond, which will result in user 33 being = me (user 1000).
Now all containers can write where they need to, and I can edit the project files as an unprivileged user.
Related
I am running my flask project from uwsgi on nginx. But my nginx is not routing the request to uwsgi when i hit localhost:80/
My nginx.conf looks like this
server {
listen 80;
server_name <your machine ip/domain>;(if on local it would be localhost but I was running on WSL so I put it IP)
location / {
include uwsgi_params;
uwsgi_pass web_app:5000; (you might see suggestion of .sock files or suffixing http:// or unix: but none work for me plain simple your python server's service name which you would provide in docker-compose)
}
}
docker-compose looks like this
version: '3.7'
services:
web_app:
build: .
container_name: kpi-dashboard
ports:
- 5000:5000
depends_on:
- db
nginx:
build: ./nginx
container_name: nginx
restart: always
ports:
- "80:80"
depends_on:
- web_app
db:
image: postgres:13-alpine
container_name: postgresql
volumes:
- postgres_data:/var/lib/postgresql/data/
environment:
- POSTGRES_USER=postgres
- POSTGRES_PASSWORD=postgres
- POSTGRES_DB=postgres
ports:
- 5432:5432
volumes:
postgres_data:
nginx dockerfile
FROM nginx
RUN rm /etc/nginx/conf.d/default.conf (it is important to remove the default conf as it would not take your custom conf no matter where you copy it)
COPY nginx.conf /etc/nginx/conf.d/
(there are answers online to copy it no other places but this only works)
EXPOSE 80
web app dockerfile
FROM python:3.8.16-slim-buster
RUN apt-get update
RUN apt-get install gcc -y && apt-get install python3-dev -y && apt-get install libpq-dev -y
ENV PYTHONPATH=${PYTHONPATH}:${PWD}
RUN pip install poetry
WORKDIR /app
COPY pyproject.toml /app/
COPY . /app/
RUN poetry config virtualenvs.create false
RUN poetry install --no-dev
EXPOSE 5000
CMD ["uwsgi", "--ini", "wsgi.ini"]
wsgi.ini file
[uwsgi]
module = app (this is when you are writing you project entrypoint in app.py. if you are writing in wsgi.py then this would become wsgi:app)
socket = 0.0.0.0:5000
callable = app (this is important as wsgi by default considers your app instance as application either handle it in your main file or just add this configuration)
processes = 1
threads = 1
master = true
vacuum = true
die-on-term = true
This is what the nginx container output looks like
Editing question as the 404 issue was solved. But nginx is still not routing to wsgi.
The solution
changed the location of copying the nginx.conf file in nginx dockerfile
COPY nginx.conf /etc/nginx/nginx.config
Editing question again as nginx routing to wsgi issue also resolved.
The solution
updated files as mentioned above
Yes so this worked for me. There are n number of configurations available online and almost all are same yet a slight difference causes the issue.
I am updating my question to change files with the content that worked. Hope it helps someone.
Intro:
I am trying to run a few WP-CLI commands for maintenance as a part of my release process on my production sites. I can execute the following commands against the docker-compose file below successfully.
docker-compose run wp-cli_collinmbarrett-com core update
docker-compose run wp-cli_collinmbarrett-com plugin update --all
docker-compose run wp-cli_collinmbarrett-com theme update --all
docker-compose run wp-cli_collinmbarrett-com db optimize
I have a plugin (WP-Sweep) installed on the site that adds its own WP-CLI command. When I try to run this command, it fails.
docker-compose run wp-cli_collinmbarrett-com sweep --all
/usr/local/bin/docker-entrypoint.sh: exec: line 15: sweep: not found
In a non-dockerized setup, I have verified that the WP-Sweep command for WP-CLI works successfully.
Question:
How can I run plugin-installed WP-CLI commands when running in a containerized environment with Docker Compose? Do I need to somehow make the WP-CLI container aware of the installed plugins other than having a shared volume?
My docker-compose.yml:
version: "3.7"
services:
wp_collinmbarrett-com:
image: wordpress:fpm-alpine
restart: always
networks:
- reverse-proxy
- collinmbarrett-com
depends_on:
- mariadb_collinmbarrett-com
volumes:
- collinmbarrett-com_files:/var/www/html
mariadb_collinmbarrett-com:
image: mariadb:latest
restart: always
networks:
- collinmbarrett-com
volumes:
- collinmbarrett-com_data:/var/lib/mysql
wp-cli_collinmbarrett-com:
image: wordpress:cli
networks:
- collinmbarrett-com
volumes:
- collinmbarrett-com_files:/var/www/html
networks:
reverse-proxy:
external:
name: wp-host_reverse-proxy
collinmbarrett-com:
volumes:
collinmbarrett-com_files:
collinmbarrett-com_data:
Full config on GitHub.
Not answering directly to your command needs (I didn't tried yet), but I wanted to share with you all the configurations I'm using in hope it helps you.
My docker-compose.yml has:
services:
...
# Mysql container
db:
...
# Wordpress container
wp:
...
wpcli:
image: wordpress:cli
user: "33:33"
volumes:
# necessary to write to the filesys
- ./php-config/phar.ini:/usr/local/etc/php/conf.d/phar.ini
- wp_app:/var/www/html
- /tmp/wp-temp:/tmp/wp-temp
environment:
HOME: /tmp/wp-temp
WORDPRESS_DB_HOST: db
WORDPRESS_DB_USER: $WORDPRESS_DB_USER
WORDPRESS_DB_PASSWORD: $WORDPRESS_DB_PASSWORD
WORDPRESS_DB_NAME: $WORDPRESS_DB_NAME
depends_on:
- db
- wp
volumes:
wp_app: {}
...
Please note that as mentioned on Running as an arbitrary user section in https://hub.docker.com/_/wordpress:
When running WP-CLI via the cli variants of this image, it is
important to note that they're based on Alpine, and have a default
USER of Alpine's www-data, whose UID is 82 (compared to the
Debian-based WordPress variants whose default effective UID is 33), so
when running wordpress:cli against an existing Debian-based WordPress
install, something like --user 33:33 is likely going to be necessary
(possibly also something like -e HOME=/tmp depending on the wp command
invoked and whether it tries to use ~/.wp-cli)
You will need to define WP-CLI user as www-data with user id and group id = 33. This is why I defined user: "33:33". Also, the command might need to download temporary content, so I defined a HOME environment setting. Please also note that HOME mapped in your Host should also be assigned with user 33:33 ownership ids, otherwise WP CLI can't write to the filesys.
Also, PHP.ini in the WPCLI image has the setting phar.readonly as On, so you need to override it. I've add a specific ./php-config/phar.ini file that has that override:
phar.readonly = Off
To execute a plugin installation I do, on my docker-compose.yml folder, the following command:
docker-compose run --rm wpcli plugin install wp-mail-smtp --force --allow-root
Please note that --force --allow-root are optional.
Error:
The uploaded file could not be moved to wp-content/uploads/.../....
Environment:
Wordpress Docker image is created from a base Wordpress image then the files are mapped in and out, for development:
version: '3'
services:
wordpress:
restart: always
environment:
WORDPRESS_DB_NAME: ...
WORDPRESS_DB_HOST: ...
WORDPRESS_DB_USER: ...
WORDPRESS_DB_PASSWORD: ...
image: wordpress:latest
ports:
- 38991:80
volumes:
- ./:/var/www/html
We talk to a dev database hosted external to the Docker container.
Image is built - and sent up to the server. Then, CMS user attempts to upload an image and the Wordpress build moans that the uploaded file could not be moved to wp-content/uploads/.../.... We don't get this error on localhost.
Could some devops experts kindly point us in the right direction on what needs to be done for this to tally up on the server.
The permissions are incorrect on the wp-content/uploads directory. I had the same error and in my case the upload folder's permissions and user/group where set wrong and also some folders inside were set to root. But that's probably because I imported a backup.
To fix the upload you can add the following two commands to your deploy pipeline/script or use docker exec -it <container-name> bash to perform it manually on the container.
Set the correct user/group on the uploads folder: $ chown -R www-data:www-data uploads/*
Set the correct permissions: $ chmod 755 uploads/*
Issue
My main goal is to create a wordpress container on my linux machine for development on that container.
Therefore, I'm creating new volumes for the plugins and themes folders and even add read & write permissions, with the :rw option.
However, when I'm trying to create a new directory or file in those "volumes", I get an error message (especially in VS Code), that tells that I don't have the permission to add these volumes.
Moreover, the permissions based on the ll command shows that the owner is the only one with the w permissions. It means that I cannot use the group www-data and add it to my user in order to edit those volumes.
When I'm trying to run chmod 766 themes plugins, the volumes are not bind anymore, so this solution doesn't work.
I've searched the whole web (including stack overflow), but none of the answers didn't work for me, so I'm lost :(
Here are some details that can help you with finding solution, including the docker-compose.yml file.
Details
Error on VS Code when trying to add a directory named hello
A system error occurred (EACCES: permission denied, mkdir '~/Workspace/WordpressProject/themes/hello')
Run mkdir hello in terminal, returns this error
mkdir: cannot create directory ‘hello’: Permission denied
ll command result for volumes
drwxr-xr-x 2 www-data www-data 4096 Jun 14 23:54 plugins/
drwxr-xr-x 5 www-data www-data 4096 May 17 22:00 themes/
docker-compose.yml
version: '3'
services:
wordpress:
image: wordpress
links:
- mariadb:mysql
environment:
- WORDPRESS_DB_PASSWORD=${Database Name}
ports:
- "127.0.0.101:80:80"
hostname: ${Wordpress Host}
volumes:
- ./plugins:/var/www/html/wp-content/plugins:rw
- ./themes:/var/www/html/wp-content/themes:rw
restart: always
mariadb:
image: mariadb
environment:
- MYSQL_ROOT_PASSWORD=${Password}
- MYSQL_DATABASE=${Database Name}
volumes:
- ./database:/var/lib/mysql
restart: always
Versions
OS: Ubuntu 18.04 LTS
Docker: v18.05.0-ce, API v1.37
Editor (Visual Studio Code): v1.23.1
Please in VS terminal execute:
sudo chown -R $USER <directory_project>
I come here because I develop an app with Symfony3. And I've some questions about the deployment of the app.
Actually I use docker-compose:
version: '2'
services:
nginx:
build: ./docker/nginx/
ports:
- 8081:80
volumes:
- .:/home/docker:ro
- ./docker/nginx/default.conf:/etc/nginx/conf.d/default.conf:ro
- ./docker/nginx/nginx.conf:/etc/nginx/nginx.conf:ro
networks:
- default
php:
build: ./docker/php/
volumes:
- .:/home/docker:rw
- ./docker/php/php.ini:/usr/local/etc/php/conf.d/custom.ini:ro
working_dir: /home/docker
networks:
- default
dns_search:
- php
db:
image: mariadb:latest
ports:
- 3307:3306
environment:
- MYSQL_ROOT_PASSWORD=collectionManager
- MYSQL_USER=collectionManager
- MYSQL_PASSWORD=collectionManager
- MYSQL_DATABASE=collectionManager
volumes:
- mariadb_data:/var/lib/mysql
networks:
- default
dns_search:
- db
search:
build: ./docker/search/
ports:
- 9200:9200
- 9300:9300
volumes:
- elasticsearch_data:/usr/share/elasticsearch/data
networks:
- default
dns_search:
- search
volumes:
mariadb_data:
driver: local
elasticsearch_data:
driver: local
networks:
default:
nginx is clear, engine is PHP-FPM with some extensions and composer, db is MariaDB, and search ElasticSearch with some plugins.
Before I don't use Docker and to deploy I used Megallanes or Deployer, when I want to deploy webapp.
With Docker I can use the docker-compose file and recreate images and container on the server, I also can save my containers in images and in tar archive and load it on the server. It's okay for nginx, and php-fpm, but what about elasticsearch and the db ? Because I need to keep data in for future update of the code. Then when I deploy the code I need to execute a Doctrine Migration and maybe some commands, and Deployer do it perfectly with some other interresting things. And how I deploy the code with Docker ? Can we use both ? Deployer for code and Docker for services ?
Thanks a lot for your help.
First of all , Please try using user-defined networks, they have additional features vs legacy linking like Embedded DNS. Meaning you can call other containers on the same network with their names in your applications. Containers on a User defined network are isolate from containers on another User defined network.
To create a user defined network:
docker network create --driver bridge <networkname>
Dockerfile to use user defined network example:
search:
restart: unless-stopped
build: ./docker/search/
ports:
- "9200:9200"
- "9300:9300"
networks:
- <networkname>
Second: I noticed you didnt use data volumes for you DB and ElasticSearch.
You need to mount volumes at certain points to keep your persistant data.
Third: When you export your containers it wont contain mounted volumes. You need to back up volume data and migrate it manually.
To backup volume data:
docker run --rm --volumes-from db -v $(pwd):/backup ubuntu tar cvf /backup/backup.tar /dbdata
The above command will create a container, mounts volumes from DB container and mounts current directory in container as /backup , uses ubuntu image and tar command to create a backup of /dbdata in container (consider changing this to your dbdirectory) in the /backup that is mounted from your docker hosts). after the operation completes the transient container will be removed (ubuntu container we used for creating the backup with --rm switch).
To restore:
You copy the tar archive to the remote location and create your container with empty mounted volume. then extract the tar archive in that volume using the following command.
docker run --rm --volumes-from dbstore2 -v $(pwd):/backup ubuntu bash -c "cd /dbdata && tar xvf /backup/backup.tar --strip 1"