Background
I'm trying to use Wercker to run my test for a PHP application. Wercker uses Docker containers to setup a test environment to execute tests in. It uses Environment Variables to expose the connection params for any connected services like MySQL and Elasticsearch. Example MYSQL_PORT_3306_TCP_ADDR = 127.0.1.1
My core Docker containers is running Ubuntu 14.04 with PHP and Apache already installed on the container.
Problem
I can't seem to access the Environment Variables via php $_SERVER or $_ENV when running via Apache. It works fine if I run the script via CLI php ./db_connect.php or if I run PHP using its build in server php -S localhost:8000. However If I try and access a page via the Apache virtual host, the Environment Variables are not available.
Progress
I have setup Apache with the mod used to allow environmental variables "I think"
sudo a2enmod env
sudo service apache2 restart
I'm trying to access the Environment Variables in my script.
$database_host = $_SERVER["MYSQL_PORT_3306_TCP_ADDR"];
$database_username = $_SERVER["MYSQL_ENV_MYSQL_USER"];
$database_password = $_SERVER["MYSQL_ENV_MYSQL_PASSWORD"];
$database_name = $_SERVER["MYSQL_ENV_MYSQL_DATABASE"];
$elasticsearch_host = $_SERVER["ELASTICSEARCH_PORT_9300_TCP_ADDR"];
I can add new variables in my .htaccess, I just don't get all the system environmental variables.
SetEnv TEST_VAR test
I have read this question How to get system environment variables into PHP while running CLI & Apache2Handler? but i'm not sure what its suggesting to do.
Question
How do I expose System Environment Variables to Apache and PHP?
If you are using php official Docker image you have to explicitly pass environment variables from Apache to PHP.
You can do something like this:
In your Dockerfile:
FROM php:7.2-apache
RUN echo 'SetEnv MYSQL_USER ${MYSQL_USER}' > /etc/apache2/conf-enabled/environment.conf
environment.conf is an arbitrary name, but it should be placed in /etc/apache2/conf-enabled/.
In docker-compose.yml:
version: '2'
services:
yourservice:
build: ./yourimage
image: yourimage
ports:
- 8080:80
volumes:
- ../html:/var/www/html
environment:
MYSQL_USER: foo
In your PHP script:
echo getenv('MYSQL_USER');
Here is the solution:
Docker will pass these to apache but you have to configure apache to make them available to PHP.
Setup the values in your local .env file
MYSQL_PORT_3306_TCP_ADDR=1234
MYSQL_ENV_MYSQL_USER=development
MYSQL_ENV_MYSQL_PASSWORD=password
Then add these as environment params in the docker-compose.yml file
version: 2
services:
web:
build: php:5.6-apache
environment:
MYSQL_PORT_3306_TCP_ADDR:${MYSQL_PORT_3306_TCP_ADDR}
MYSQL_ENV_MYSQL_USER: ${MYSQL_ENV_MYSQL_USER}
MYSQL_ENV_MYSQL_PASSWORD: ${MYSQL_ENV_MYSQL_PASSWORD}
Then to pass these to PHP set these as environment params in your Virtual Host config
<VirtualHost *:80>
ServerName some-project
ServerAdmin webmaster#localhost
DocumentRoot /var/www/some-project
# Set apache environment variables
SetEnv MYSQL_PORT_3306_TCP_ADDR ${MYSQL_PORT_3306_TCP_ADDR}
SetEnv MYSQL_ENV_MYSQL_USER ${MYSQL_ENV_MYSQL_USER}
SetEnv MYSQL_ENV_MYSQL_PASSWORD ${MYSQL_ENV_MYSQL_PASSWORD}
</VirtualHost>
These will now be available to access in PHP via the $_SERVER super global array.
<?php
echo $_SERVER['MYSQL_ENV_MYSQL_USER'];
if you're using php-fpm, you can pass env vars from OS to PHP-FPM through clear_env ini setting in a file like /path/to/php/fpm/pool.d/www.conf:
clear_env = no
it works with environment vars set via docker-compose.yml as below:
version: "..."
services:
php-fpm:
image: php:7-fpm
environment:
MY_VAR: my-value
IMPORTANT: Of course, the risk is that your PHP-FPM will get access to all OS env vars. If passing all vars is a problem, you can also pass only specific vars via www.conf or another php ini config file:
; Pass environment variables like LD_LIBRARY_PATH. All $VARIABLEs are taken from
; the current environment.
env[MY_VAR] = $MY_VAR
With docker-compose you can retrieve the operating system's environment variables set with the environment option of the docker-compose.yml file through php's $_ENV variable.
version: 2
services:
web:
build: php:5.6-apache
environment:
MYSQL_USER: "user"
MYSQL_PASSWORD: "passwd"
should give you
$_ENV['MYSQL_USER'] = user
$_ENV['MYSQL_PASSWORD'] = passwd
I'm not sure how Wercker maps environment variables to the containers, but there's this open issue that I think might help
https://github.com/wercker/wercker/issues/63
you can check get env with php command like below
php -r "echo getenv('MYSQL_USER');"
Related
I'm building my app for local development using docker-compose.yaml, using the two Dockerfiles - one for app (WordPress), and another for nginx. Since this is a specific app, that is built using Jenkins pipeline, I cannot change the Dockerfiles, but I would like to be able to have the same environment to test on locally as I have on the staging and production servers.
The php part works but nginx fails. The Dockerfile for nginx looks like this:
FROM nginx:latest
COPY scripts/docker-nginx-entrypoint.sh /docker-nginx-entrypoint.sh
COPY ./config/nginx.conf /opt/nginx.conf
COPY ./config/nginx.conf.prd /opt/nginx.conf.prd
COPY --from=DOCKER_IMAGE_NAME_PHP /var/www/html/ /var/www/html/
CMD ["/bin/bash","/docker-nginx-entrypoint.sh"]
The DOCKER_IMAGE_NAME_PHP part fails with
ERROR: Service 'nginx' failed to build: invalid from flag value DOCKER_IMAGE_NAME_PHP: invalid reference format: repository name must be lowercase
In my docker-compose.yaml for the nginx part I have
nginx:
build:
context: .
dockerfile: Dockerfile.static
container_name: web-service
working_dir: /var/www
volumes:
- .:/var/www
environment:
- "DOCKER_IMAGE_NAME_PHP=app-admin"
- "DOCKER_IMAGE_NAME_NGINX=web-service"
depends_on:
- app
ports:
- 8090:80
I thought that setting the environment in the compose file would be enough, and that this will be used (the app-admin is the container_name of the php part with WordPress).
In my Jenkins pipeline scripts, these names are used to build the app and static images manually (using docker build -t DOCKER_IMAGE_NAME_PHP -f Dockerfile.php), and then the names are set to env like
echo -e "DOCKER_IMAGE_NAME_PHP=$DOCKER_IMAGE_NAME_PHP" >>env
EDIT
Like the answer suggested I've tried with adding args under build key
build:
context: .
dockerfile: Dockerfile.static
args:
- "DOCKER_IMAGE_NAME_PHP=app-admin"
Then in my Dockerfile I've added
FROM nginx:latest
COPY scripts/docker-nginx-entrypoint.sh /docker-nginx-entrypoint.sh
COPY ./config/nginx.conf /opt/nginx.conf
COPY ./config/nginx.conf.prd /opt/nginx.conf.prd
ARG DOCKER_IMAGE_NAME_PHP
COPY --from=$DOCKER_IMAGE_NAME_PHP /var/www/html/ /var/www/html/
CMD ["/bin/bash","/docker-nginx-entrypoint.sh"]
But I still get the error. I've tried with ${DOCKER_IMAGE_NAME_PHP}, but that doesn't help.
The odd thing is that adding RUN echo $DOCKER_IMAGE_NAME_PHP, when I run this, I can see
Step 6/8 : RUN echo $DOCKER_IMAGE_NAME_PHP
---> Running in 0801fcd5b77f
app-admin
But it's not recognized in the COPY command. How come?
EDIT 2
So it turns out I cannot do this:
https://github.com/moby/moby/issues/34482
Because the --from expects the image name (which I'm trying to pass to it from the previously build service but in my case it's dynamic). This works in the Jenkins since I'm doing a docker build command, and the variables are available in the bash script...
COPY --from does not support variables, but FROM does.
the following example uses multi-stage build, to help you extract whatever you need from the first image.
ARG DOCKER_IMAGE_NAME_PHP=php:7.3
FROM ${DOCKER_IMAGE_NAME_PHP} as php-image
FROM nginx:latest
COPY scripts/docker-nginx-entrypoint.sh /docker-nginx-entrypoint.sh
COPY ./config/nginx.conf /opt/nginx.conf
COPY ./config/nginx.conf.prd /opt/nginx.conf.prd
COPY --from=php-image /var/www/html/ /var/www/html/
CMD ["/bin/bash","/docker-nginx-entrypoint.sh"]
an almost similar example sits in the docs
For that, you must use ARG in the Dockerfile.
https://docs.docker.com/engine/reference/builder/#arg
environment in docker-compose.yml is not available when you're building.
https://docs.docker.com/compose/compose-file/#environment
You can use arg in the docker-compose.yml too:
https://docs.docker.com/compose/compose-file/#args
I've created a Docker container with an Ubuntu base image. Setting the environment variables through a .env file. When running the container, I can see the variables being passed through using the shell terminal.
I want to able to get the env varibles in my wp-config. I am using getenv but it is not working..
Any suggestions..
Thanks
You can set the environment variable for your docker container in 2 ways
In docker run command use docker run -e VARIABLE=VALUE ...
In docker-compose file you can set in like:
environment:
- DEBUG=1
https://docs.docker.com/compose/environment-variables/#set-environment-variables-in-containers
You use .env file, so you certainly use docker-compose. If not use docker-compose, .env will not make effect. And the .env file must be placed in the directory where docker-compose is run from.
Whole solution could be something like:
.env
MY_VARIABLE=abc
docker-compose.yml
version: '3'
services:
my_service:
environment:
- MY_VARIABLE="${MY_VARIABLE}"
wp-config.php
echo getenv('MY_VARIABLE');
I guess you did not get env because you did not do - MY_VARIABLE="${MY_VARIABLE}" in docker-compose.yml, the value in .env will not be automatically act as an environment variable to container, you need to handle it in compose file. FYI.
Detail refers to offical guide
Both previous answers, I could already pass the env variables to my apache environment served by docker. I just needed to add Pass env_name to the .htaccess file for each env variable.
I could then get the values via the $SERVER['env_name'] within my php application..
I have a docker container :
services:
php-fpm:
build:
context: ./docker/php-fpm
volumes:
- ./symfony:/home/home
container_name: php
ports:
- "9004:9001"
networks:
- local
working_dir: /home/home
environment:
- DATABASE_HOST=test
- DATABASE_PORT=
- DATABASE_NAME=test
I made :
docker-compose build --no-cache
docker-compose up
clear cache
When I refresh the page I get : Environment variable not found: "DATABASE_HOST".. What's the problem I don't understand. I spent a lot of time analyze this issue. Have you an idea about that ? Thx in advance. Btw when I do docker inspect I see all this environment variables assigned.
I've run into this problem myself. You have to explicitly map the environment variables you want to make accessible to php/symfony in php-fpm.conf like:
[www]
env[MY_ENV_VAR_1] = 'value1'
env[MY_ENV_VAR_2] = 'value2'
However that doesn't seem to work with actual enviornment variables from the host!.
There is a long discussion of that here (along with several, what seem to me, laborious work-arounds to the problem: https://groups.google.com/forum/#!topic/docker-user/FCzUbjTIp_0
I've successfully done it in the pool.d configuration file like so:
env[DATABASE_HOST] = $DATABASE_HOST
env[DATABASE_PORT] = $DATABASE_PORT
env[DATABASE_NAME] = $DATABASE_NAME
I just add this in as part of the docker file:
ADD fpm/app.pool.conf /etc/php5/fpm/pool.d/
If you extend from the official PHP Docker image, it sets clear_env = no for you or you can set it yourself in your image's pool config.
Here's the line adding clear_env = no to the config in the official image. You just need to add this to your FPM pool config, or you can add them one-by-one if you prefer as shown by Robert.
I'm trying to deploy a very simple Symfony application using nginx & php-fpm via Docker.
Two docker services :
1. web : running nginx
2. php : running php-fpm; containing application source.
I want to build images that can be deployed without any external dependency.
That's why I'm copying source code within the php container.
On development process; i'm overriding /var/www/html volume with local path.
# file: php-fpm/Dockerfile
FROM php:7.1-fpm-alpine
COPY ./vendor /var/www/html
COPY . /var/www/html
VOLUME /var/www/html
Now the docker-compose configuration file.
# file : docker-compose-prod.yml
version: '2'
services:
web:
image: "private/web"
ports:
- 80:80
volumes_from:
- php
php:
image: "private/php"
ports:
- 9000:9000
The problem is about permissions.
When accessing localhost, Symfony is botting up, but cache / logs / sessions folders are not writable.
nginx is using /var/www/html to serve static files.
php-fpm is using /var/www/html to execute php files.
I'm not sure about the problem.
But how can I be sure about the following:
/var/www/html have to be readable for nginx ?
/var/www/html have to be writable for php-fpm ?
Note: I'm building images from MacbookPro; cache / logs / sessions are 777.
docker-compose.yml supports a user directive under services. The docs only mention it in the run command, but it works the same.
I have a similar setup and this is how I do it:
# file : docker-compose-prod.yml
version: '2'
services:
web:
image: "private/web"
ports:
- 80:80
volumes_from:
- php
php:
image: "private/php"
ports:
- 9000:9000
user: "$UID"
I have to run export UID before running docker-compose and then that sets the default user to my current user. This allows logging / caching etc. to work as expected.
I am using this solution "Docker for Symfony" https://github.com/StaffNowa/docker-symfony
New features on
./d4d start
./d4s stop
./d4d help
I've found a solution;
But if someone can explain best practices, it will be appreciate !
Folders cache / logs / sessions from docker context where not empty (on host).
Now that folders have been flushed, Symfony creates them with good permissions.
I've found people using usermod to change UID, ie: 1000 for www-data / nginx ...
But it seems to be an ugly hack. What do you think about ?
I have an Docker container running nginx and php-fpm using supervisord.
I am trying to use .ebextensions/*.config to set up environment variables.
Although the variables are set up in the container (e.g # echo $VAR prints the expected value), I can't find an easy way to make them available to PHP. IMHO I could only write a bash script to read and copy the vars to www.conf or to nginx host config as fcgi_param. But then this script will need to know which variables to copy... .
I am wondering if anyone found an easier way to do this.
I wrote bash script which will copy env vars starting with a list of prefixes to the fpm's www.conf file and baked it into my image's start.sh script.
This still won't put variables in $_ENV :( but will add them to $_SERVER and are available via getenv().
Script is here: adrian7/php-transfer-vars.sh
There are two ways to do this with any reliability. For all of the web side stuff set the environment variables in an .htaccess file. You could do this for your database connection information, for example:
# environment variables
SetEnv DBL "mysql:dbname=mydatabase;host=localhost;port=3306"
SetEnv DB_USER "root"
SetEnv DB_PASS "fruitygoodness"
Place the .htaccess file in the web root in your container. When you need the environment variables you can retrieve them with PHP's getenv().
define('DBL', getenv('DBL'));
define('USER', getenv('DB_USER'));
define('PASS', getenv('DB_PASS'));
For the PHP-CLI inside the container you would specify the environment variables in the Docker run command by specifying the option -e prior to each variable. Here is an example:
sudo docker run --name mysite -e "DBL=mysql:dbname=mydatabase;host=localhost;port=3306" -e "DB_USER=root" -e "DB_PASS=fruitgoodness" -p 80:80 -p 443:443 -P -d repo/mysite
Doing this makes the environment variables available to the container but not to the web server running in the container.