To test docker stack deploy --compose-file
function, I load one of my sample docker-compose.yml
:
version: '3'
services:
nginx:
image: "${DOCKER_USER}/lnmp-nginx:v1.2"
build:
context: .
dockerfile: Dockerfile.nginx
ports:
- "80:80"
networks:
- frontend
depends_on:
- php
php:
image: "${DOCKER_USER}/lnmp-php:v1.2"
build:
context: .
dockerfile: Dockerfile.php
networks:
- frontend
- backend
environment:
MYSQL_PASSWORD: Passw0rd
depends_on:
- mysql
mysql:
image: mysql:5.7
volumes:
- mysql-data:/var/lib/mysql
environment:
TZ: 'Asia/Shanghai'
MYSQL_ROOT_PASSWORD: Passw0rd
command: ['mysqld', '--character-set-server=utf8']
networks:
- backend
volumes:
mysql-data:
networks:
frontend:
backend:
In the image
section of service nginx
and php
, I used ${DOCKER_USER}
to get the docker id from environment variables. And if I use docker-compose up
, it will load .env
file as default envvar files, which content is:
DOCKER_USER=twang2218
However, if I use docker stack
to deploy this docker-compose.yml
, I will got following errors:
$ docker stack deploy --compose-file docker-compose.yml lnmp
Ignoring unsupported options: build
Creating network lnmp_frontend
Creating network lnmp_backend
Creating network lnmp_default
Creating service lnmp_php
Error response from daemon: rpc error: code = 3 desc = ContainerSpec: "/lnmp-php:v1.2" is not a valid repository/tag
As you can see, as docker stack deploy
command didn't load .env
file, the ${DOCKER_USER}
was replaced by empty string, which cause image name become invalid.
If .env
file was loaded, the final image name should be twang2218/lnmp-php:v1.2
.
The environment substitution is actually working, if I run the command this way:
$ DOCKER_USER=twang2218 docker stack deploy --compose-file docker-compose.yml lnmp
Ignoring unsupported options: build
Creating network lnmp_frontend
Creating network lnmp_backend
Creating network lnmp_default
Creating service lnmp_mysql
Creating service lnmp_nginx
Creating service lnmp_php
And we can verify it's working by docker service inspect
command:
$ docker service inspect lnmp_php | grep Image
"Image": "twang2218/lnmp-php:v1.2@sha256:4f1aef1350aeef3f757f6b6da8f2e1a79ff849f61382320e4b668bfe2b0d1c5a",
The image name is twang2218/lnmp-php:v1.2
, which is correct.
I tested this feature on Digtial Ocean droplet, which installed docker 1.13.0-rc2 via docker-machine
.
Here is the version:
$ docker version
Client:
Version: 1.13.0-rc2
API version: 1.25
Go version: go1.7.3
Git commit: 1f9b3ef
Built: Wed Nov 23 06:32:39 2016
OS/Arch: linux/amd64
Server:
Version: 1.13.0-rc2
API version: 1.25
Minimum API version: 1.12
Go version: go1.7.3
Git commit: 1f9b3ef
Built: Wed Nov 23 06:32:39 2016
OS/Arch: linux/amd64
Experimental: false
Here is the docker info
:
root@d1:~/docker-lnmp# docker info
Containers: 7
Running: 1
Paused: 0
Stopped: 6
Images: 4
Server Version: 1.13.0-rc2
Storage Driver: aufs
Root Dir: /var/lib/docker/aufs
Backing Filesystem: extfs
Dirs: 43
Dirperm1 Supported: true
Logging Driver: json-file
Cgroup Driver: cgroupfs
Plugins:
Volume: local
Network: bridge host macvlan null overlay
Swarm: active
NodeID: vyf3mgcj3uonrnh5xxquasp38
Is Manager: true
ClusterID: jb8rxvd6ptrn3psfkiixxed7r
Managers: 1
Nodes: 3
Orchestration:
Task History Retention Limit: 5
Raft:
Snapshot Interval: 10000
Number of Old Snapshots to Retain: 0
Heartbeat Tick: 1
Election Tick: 3
Dispatcher:
Heartbeat Period: 5 seconds
CA Configuration:
Expiry Duration: 3 months
Node Address: 138.197.195.206
Manager Addresses:
138.197.195.206:2377
Runtimes: runc
Default Runtime: runc
Init Binary: docker-init
containerd version: 03e5862ec0d8d3b3f750e19fca3ee367e13c090e
runc version: 51371867a01c467f08af739783b8beafc154c4d7
init version: 949e6fa
Security Options:
apparmor
seccomp
Profile: default
Kernel Version: 4.4.0-51-generic
Operating System: Ubuntu 16.04.1 LTS
OSType: linux
Architecture: x86_64
CPUs: 1
Total Memory: 488.5 MiB
Name: d1
ID: E6UB:PHX6:I2KY:Q35T:PCCI:MFDQ:ZMMN:2X7K:DEOZ:PAP7:4BUC:FP6X
Docker Root Dir: /var/lib/docker
Debug Mode (client): false
Debug Mode (server): false
Registry: https://index.docker.io/v1/
WARNING: No swap limit support
Labels:
provider=digitalocean
Experimental: false
Insecure Registries:
127.0.0.0/8
Live Restore Enabled: false
This is by design. The .env
support is a feature of Compose, not of the file format.
We can discuss adding this for a future release, but I don't know if it's really the best option.
The .env
support is quite useful in Compose, we used it in many of our compose files. It separates dynamic parts and static parts of docker-compose.yml
file. With load .env
by default, we can just provides different .env
file for different environments, and keeping the docker-compose.yml
and related scripts static.
It's not possible to use env_file
or environment
in docker-compose.yml
to achieve the same envvars substitution result. .env
is the most easy way to do it.
Otherwise, we have to prefix export
in each line of .env
file and manually source .env
every time before loading the docker-compose.yml
, and the extra steps sometimes are prone to mistake.
I've just noticed this.
I assumed/expected it to work in the same way it does for Compose, but is not the case for docker deploy
.
In my particular case, I'm was expecting to use the .env
file to store sensitive data (passwords, API keys, etc) used in the services I'll be creating in the stack:
version: '3'
volumes:
data:
driver: local
networks:
backend:
driver: overlay
services:
rabbitmq:
image: rabbitmq:${EXCHANGE_RABBITMQ_TAG}
volumes: [ "data:/var/lib/rabbitmq" ]
logging: { driver: gelf, options: { gelf-address: "udp://0.0.0.0:12201" } }
networks: [ "backend" ]
ports: [ "15672:15672", "5672:5672" ]
environment:
RABBITMQ_DEFAULT_USER: ${EXCHANGE_RABBITMQ_USER}
RABBITMQ_DEFAULT_PASS: ${EXCHANGE_RABBITMQ_PASS}
deploy:
replicas: 1
restart_policy:
condition: on-failure
placement:
constraints:
- node.labels.queue-host == true
While this Compose file will be checked in on Git, the .env
file would be ignored.
I've followed the whole stuff/history of the *.dab vs compose files, and I feel you guys are trying to avoid something - or proposing a better solution - but I lost track of the whole discussion...
Hello All,
Docker version: v1.13.0-rc4
I am getting error : Ignoring unsupported options: build, Does it mean it will not create build from Dockerfile ?
And also getting same error for network_mode: Ignoring unsupported options: network_mode.
Below is command:
DOCKER_IMAGE=akhil123 docker stack deploy -c docker-compose.yml foo
Many thanks in advance.
@akhildangore please don't comment on issues with questions that are not directly related. The docker stack deploy
feature, _by design_ does not perform builds. Reason for this is that a _build_ is performed on the host that the command is run from, so the image will only be available on _that_ node. When deploying that image in a Swarm, the service cannot be started on other nodes. To deploy services, make sure the image you're deploying is pushed to a registry (or for testing; make sure the image is available on every node in the swarm)
Are there any cases/discussion in favor of/against supporting this behavior on docker deploy
?
@vovimayhem no decision was made yet on .env
file, but you may be interested in https://github.com/docker/docker/pull/30144, which adds support for secrets to the compose file
I've just found that discussion. Excellent!
I am using a bash function as a workaround.
You may adapt it to your needs until the secrets
feature be released:
dsd() {
stack=${1:-${PWD##*/}} # by default, the name of the cointaining folder
compose_file=${2:-docker-compose.yml}
if [ ! -f $compose_file ]; then
echo "Misses compose file: $compose_file" >&2
return 1
fi
# execute as a subcommand in order to avoid the variables remain set
(
# export variables excluding comments
[ -f .env ] && export $(sed '/^#/d' .env)
# Use dsd your_stack your_compose_file to override the defaults
docker stack deploy --compose-file $compose_file $stack
)
}
For those subscribing to this issue; secrets support for docker-compose files will be included in the 1.13.1 release, which should be not too far in the future
@whoan I'm using this as a workaround:
env $(cat .env | grep ^[A-Z] | xargs) docker stack deploy --compose-file docker-compose.yml [STACK_NAME]
That way, variables don't get stuck on the terminal window
It's always nice to have the ability to load things from a .env
file - apart from a simpler Docker secrets use-case which can now be circumvented, there are always Docker Compose values that you don't want to have hardcoded in your repo.
Let's assume you use docker stack deploy
to deploy a complete stack and you have the following requirements:
If you can't configure this with a .env
file, you need to manually change the docker-compose.yml
file before deploying the stack each time, otherwise the service scale value will revert back to 1.
You can extend the above with things like networks, configuring the DNS that a service should listen to, etc.
I can draft a PR that will load a .env
file, if one exists in the same directory as docker-compose.yml
if we believe the above uses cases make sense.
The design of docker stack
deploy is a bit different from docker-compose
commands. I don't think it makes sense to just read a .env
by default. Not even the docker-compse.yml
is read by default, because in the future the default deploy source will likely be something else.
You can always source an .env
file yourself before running stack deploy
.
Just . .env
before calling docker stack deploy
does not help, $variables are not substituted. Only env .. xargs
trick did help.
It would be nice to have --env-file=FILE
option like in docker run
.
Just . .env before calling docker stack deploy does not help
This should help @C-Pro - you need to have export ...
lines in your .env
file. Alternatively, you can do export $(cat .env)
, which would work for most cases.
Hello All,
Today I tried to run docker stack deploy
.
My docker-compose.yml
file:
version: '3'
services:
simple:
image: alpine
environment:
- FOO: ${BAR}
env_file: .env
And .env
file in the same directory:
BAR=worked
After launch docker stack deploy -c docker-compose.yml test
, I inspected container and got this:
$ env
BAR=worked
FOO=
...
Seems that, .env
provided in container, but not provided on host machine.
It means, that I can use .env
file instead of environment
section, but I can't use .env
file with Variable Substitution.
Docker version: v17.03
@ddpaimon
environment:
- FOO=${BAR}
It looks like that .env file only works for container, but not for the docker-compose.yml file variable replacement.
Docker for MAC, Docker version 17.03.1-ce, build c6d412e
@realcbb
Yes. But for using .env
file variables inside container, you must remove their in environment
section.
For example:
docker-compose.yml
...
environment:
- FOO=${FOO:-empty}
...
.env
FOO=filled
In container I got this:
$ env
FOO=empty
But if I remove FOO
from environment
section in docker-compose.yml
, I got this:
$ env
FOO=filled
@ddpaimon
Environment variables specified in environment override these values specified in .env file.
@dnephin : you state that .env is not part of the docker compose file format. However, the .env file feature is documented in the Compose file version 3 reference: https://docs.docker.com/compose/compose-file/#variable-substitution .
This gives the impression .env also should work with docker stack deploy.
Besides that, as already mentioned by others, separating actual environment specific values from the stack definition yaml is a much wanted/needed feature. Specifically we want to use it to specify image versions and replications.
Thanks, I opened https://github.com/docker/docker.github.io/issues/3654 to fix the docs
docker stack deploy
can take a generated file. This works in bash for all my variables and keeps secrets secret as well:
docker stack deploy --with-registry-auth --compose-file=<(ENV1=value1 ENV2=value2 docker-compose -f docker-compose.yaml -f docker-compose.override.yaml -f third-sample-compose.yaml config) stack-name
Please note I added the in-line ENV variables as additional ones or overrides. My compose files reference .env files and this works. Hope this is helpful 👍
The functionality of docker-compose config
is what ties this together.
I came across this issue when looking for a solution to my .env
not being read in by docker stack deploy
. I was a bit surprised to see it wasn't supported (docs could be clarified), but want to add my support for .env
, like compose.
My use case is that I use docker stack deploy
in dev, test, staging environments and use environment variables for stack options to keep the yml file the same.
Currently using one of the workarounds posted here but using a .env
file would be the preferred route.
Just a friendly reminder: There might be the possibility your'e trying to use dotenv files to store API keys, passwords & other stuff considered to be "sensitive" to put into the cluster. For these cases, you should be using Docker Secrets.
For other stuff, may I suggest having one compose file per deployed/deployable environment ? Most of the stuff that changes between different environments will be the available servers, different server organization, etc... and thus needing different values on the deploy
key contents (placement
rules, resources
reservations, etc), making using a single file for everything a bit too complicated.
Actually I want this feature, variables in compose file can be treated as different value on different host when using docker stack deploy.
"For other stuff, may I suggest having one compose file per deployed/deployable environment ? Most of the stuff that changes between different environments will be the available servers, different server organization, etc... and thus needing different values on the deploy key contents (placement rules, resources reservations, etc), making using a single file for everything a bit too complicated."
@vovimayhem Sorry to be blunt, but that doesn't make nearly as much sense as using a single compose file with variable substitution using an env_file. I'd prefer to use the env_file format as this also makes it much easier for me to provide stacks as a deliverable to my customers and train them to update a single ini-style vars files than to mess with a compose file (which I DON'T want).
Service configs are a great addition, but they don't seem usable for deployment time interpolation (e.g. $TAG).
If environment variables are supported at all, then be consistent in the mechanisms used to resolve them across tools. Stack deploy seems to choose to be inconsistent, without fundamentally changing environment variable behaviors. Secrets and service configs are better alternatives to some usages of environment variables, but they do not subsume.
You don't seem to get it @vovimayhem. I'm not talking about passing envs to containers; that works as expected. What I mean is to use an env_file that is parsed during stack deploy
as it was during compose up
.
@ntwrkguru I just thought this new feature would help you... I'm so sad it doesn't.
This still works as an alternative;
$ echo 'BAR=worked' > ./.env
$ export $(cat .env) && docker stack deploy testing -c -<<'EOF'
version: '3'
services:
simple:
image: nginx:alpine
environment:
FOO: ${BAR}
env_file: .env
EOF
$ docker inspect testing_simple -f '{{json .Spec.TaskTemplate.ContainerSpec.Env}}'
["BAR=worked","FOO=worked"]
@thaJeztah , indeed it does. I have a task in my playbook to source an environments file, but that's missing the bigger point. This used to be possible with compose
and is now not possible with stack
. IMO, that's a regression. Also, in your example, you're still passing an environment variable into the container. I can do that with the env_files
today; the issue is parsing the env_file
during the stack deploy -c docker-compose.yml
operation.
This is especially painful since stack
no longer supports multiple compose files, else one could simply use a secondary compose file per environment. To do it that way requires one to build the stack file from the compose files, introducing another step. So, either way you look at it, we went from a single-step process to a multi-step process to accomplish the same end result.
Also, FWIW, the configs
is really subpar in my experience for actual configs. I was envisioning (hoping) that I could have /application/config.conf
in source. Update that file, commit, push and CI would re-deploy the stack with the new config. That's not possible without some hackery to change the file name or some other mechanism. Surely we can checksum the file, at a minimum, or scan for content changes and update based on the file itself? All in all, it just seems like we'r'e going backwards. Throw in the support for K8s now and it makes me wonder if swarm will just languish on the vine until it loses enough usage that it's quietly dropped.
Also, FWIW, the configs is really subpar in my experience for actual configs. I was envisioning (hoping) that I could have /application/config.conf in source. Update that file, commit, push and CI would re-deploy the stack with the new config. That's not possible without some hackery to change the file name or some other mechanism.
@ntwrkguru The simple workaround is changing not the filename, but the name of the config itself. I employed a version scheme for my config names, e.g. config_v1
, config_v2
, ..
So just remember to up that version after changing the config file.
services:
app:
[...]
configs:
- source: config_v2
- target: /config.yml
configs:
config_v2:
file: ./config.yml
I understand the reasoning behind not having a versioned configs & secrets yet, so personally I am currently okay with this (easy) workaround.
Thanks @djmaze, but that's ultimately a ridiculous thing to need to do when there's inherent version tracking built in to every source control system. Also, thanks for the link; I commented there as well. I don't see why Docker cares about the version other than the one that's current. The only reason I could see for needed to version these is for rollback, but tons of things need to be tracked there as well anyway, so what's a couple more? (says the guy that doesn't have to write the code) :-)
Try this:
echo "$(docker-compose -f stack.yml config 2>/dev/null)" | docker stack deploy -c- stack_name
It uses docker-compose to parse the config file, substituting env vars, strips warnings from the output and then pipes it to docker stack deploy via stdin.
Replace '-f stack.yml' with the name of your config file or omit it to use the default docker-compose.yml.
+1
A year later and we still have to hack this to work. As of 17.09.1, docker stack deploy -f compose.yml
won't even substitute using known shell vars.
$ printenv | grep PORTAINER
PORTAINER_VER=1.14.3
portainer:
image: "portainer/portainer:${PORTAINER_VER}"
$ sudo docker stack deploy -c /tmp/docker/jedi-core.yml --with-registry-auth --prune --resolve-image always jedi-core
Updating service jedi-core_redis_server (id: 0csjyandro713y13ncitk6c0k)
Updating service jedi-core_api-gateway (id: gzcz2eturuxqkjojsc9e6954l)
Updating service jedi-core_auto_results_api (id: tw43c6e0x98q6f0m2g0zttwhf)
Updating service jedi-core_auto_results_api_mongo (id: qpwpypyzd9aigpa71xgxxdzcp)
invalid reference format
Any variables for tags will produce invalid reference format
.
A year later and we still have to hack this to work. As of 17.09.1, docker stack deploy -f compose.yml won't even substitute using known shell vars.
see How to keep Environment Variables when Using SUDO
$ export PORTAINER_VER=1.14.3
$ printenv | grep PORTAINER
PORTAINER_VER=1.14.3
$ sudo printenv | grep PORTAINER
$ sudo -E printenv | grep PORTAINER
PORTAINER_VER=1.14.3
$ cat > docker-compose.yml <<'EOF'
version: '3'
services:
portainer:
image: "portainer/portainer:${PORTAINER_VER}"
EOF
$ sudo -E docker stack deploy -c docker-compose.yml foobar
Creating network foobar_default
Creating service foobar_portainer
$ sudo docker service ls
ID NAME MODE REPLICAS IMAGE PORTS
vt4h0g8yygcg foobar_portainer replicated 1/1 portainer/portainer:1.14.3
Thanks, but any word on simply supporting variable substitution from a file?
[edit] This shouldn't be an issue (but could be) as I'm using Ansible to perform the task with become: yes
, but the user is still the same user who sources the environment vars.
I can't believe this isn't possible. We would like to keep a single stack file and be able to change deployment options using dynamic variables.
This would work but is ugly and a hack:
echo "$(docker-compose -f stack.yml config 2>/dev/null)" | docker stack deploy -c- stack_name
I've been messing with this for many hours and looks like doing some background script work (I'll be using CI to do this) to create a DAB file from these various pieces. It would be nice to be have a docker tool that would do this... :-) Maybe add a --env-file version.env
added to docker-compose bundle
?
In my use case, I want to use a version.env
"manifest" to track and control the versions of containers/images that comprise a platform. My process looks like this:
.env
file.env
file to populate the shell varsdocker-compose -f stack.yml config > docker-compose.yml
docker-compose pull
to register the image digestsdocker-compose bundle -o stack.version.dab
DAB fileAt this point, ideally I would be able to docker deploy --host manager.swarm.com --bundle-file stack.version.dab --with-registry-auth --resolve-image always stack-name
, but I get that it's not possible now. In this case, I would scp the DAB file to the manager and execute the docker deploy
.
Is this the workflow Docker had in mind @thaJeztah? Is there a better way?
[edit] This does not work since a DAB ignores volume:
, network:
, and deploy:
directives. I've taken to simply sourcing an env file to the shell, rebuilding a temp compose file, then deploying that.
I would love if .env
files were read by default like in Docker Compose and --env-file
(short -e
) would be added for docker stack deploy
to be able to override environment variables and the defaults from the .env
file.
+1
It would be quite convenient to read the .env in the first place as docker-compose does.
Either by default or just pass the env file as parameter in docker stack command line.
The two already mentioned workarounds (_find them also below_) seem to work although a little bit ugly compared to the proposed 'fix'.
_echo "$(docker-compose -f stack.yml config 2>/dev/null)" | docker stack deploy -c- stack_name_
_env $(cat .env | grep ^[A-Z] | xargs) docker stack deploy --compose-file docker-compose.yml [STACK_NAME]_
I would add that having docker-compose installed only to be able to process these variables can also be quite dangerous actually.
If anyone deploy the stack using docker-compose up -d by mistake instead of using docker stack deploy, it would most probably induce applications errors and file corruption.
Having environment variable interpolation in deploy is the best solution for continuous integration.
One issue with the use of '.env' is that it overlaps with similar file names used by, for example, Ruby on Rails, having the ability to specify an environment file by argument is superior.
@ntelisil's suggestions are well taken, they could be supplemented or modified by:
You could use envsubst (part of gnu gettext):
envsubst < infile
I used:
$ envsubst < docker-compose.yml-template > docker-compose.yml
And that worked fine, but I needed to add 3Mb or so to my container.
Nice @rnickle, but still "hacky" compared to Docker being able to do this the way it used to. It seems (and please Docker dudes correct me if I'm wrong) that there is very little effort going into swarm-mode since the announcement of K8s support, so I'm doubtful that any of these regressions will be addressed.
And that worked fine, but I needed to add 3Mb or so to my container.
If the environment variables are set, docker slack deploy
should already interpolate them
compared to Docker being able to do this the way it used to.
Docker never had this feature; docker compose had; docker compose and docker stack deploy share the _file format_ but not nescessarily all behaviors of the software itself.
that there is very little effort going into swarm-mode since the announcement of K8s support
Compose file handling is all done client side, and used both for k8s and swarmkit, so nothing slowing down in this area, other than “there’s only so much we can do at any given time”
For those waiting for that feature; the upcoming release will have support for multiple compose files for docker stack deploy
, so if you’re currently using that feature in docker compose: the upcoming docker release will support this as well
Semantics aside, thanks for the update. When I say Docker, I don't mean necessarily the daemon or engine, but the company that builds the tools. The genesis for the comment about there being little effort really stems from the fact that swarm-mode has been out for over a year and is still WAY behind where we were with a single-node using compose.
I can appreciate that they are different, but use the same file format, but that actually leads to more confusion, and potentially disappoint, when users discover that they have to trade features for using swarm. That and the fact that the DAB files are STILL being listed as experimental. Unfortunately, we made the decision to use swarm-mode in a big project, or I wouldn't even care. Fortunately, we won't make that mistake again.
[edit]
If the environment variables are set, docker slack deploy should already interpolate them
Doing this in a CI environment is a royal ass pain. Essentially, I ended up installing compose, sourcing the envvars, washing the compose file through (after pulling the images) and then spitting out a new compose file for use with stack deploy
. (And I won't even start in on how painful it is when :latest
doesn't mean :latest
in swarm-mode, since this issue is specifically about variable interpolation.)
_EDIT: I hope this post doesn't come across aggressively. I love the Docker Stack concept and I do think the whole Docker suite is pretty well supported. It just seems that Docker (the organisation) currently doesn't view its products the same way users do, which is unfortunate and appears to be the cause of most issues I've run into using Compose and Stack._
Docker never had this feature; docker compose had; docker compose and docker stack deploy share the file format but not nescessarily all behaviors of the software itself.
I feel like this statement reveals a fundamental disconnect between the way Docker's developers and users view these products. As a user, whether I'm working with Docker Engine, Docker Compose or Docker Swarm, it's all Docker and should behave consistently as far as possible.
My understanding of the purpose of these products is:
One of the key selling points of Docker (and containers in general) is easy reuse of the same app in multiple environments. Therefore, Compose should be additive to Engine and Stack should be additive to Compose. Particularly as they share the same file format, Stack not supporting features of Compose leads to confusion for developers and added complexity in CI processes.
I wouldn't say compose is for dev and stack for prod, necessarily. I view compose as being for a multi-container application or "system" and stack for multi-host deployments using swarm-mode as the scheduler/orchestrator. Otherwise, your comment is 100% spot on. I also am frustrated (if it weren't obvious by my other comments) that there is a disconnect between the developers and the users as to how the product(s) are being used.
oh, wow. I joined the confusion and pain while evaluating docker swarm for a big project as well.
The secrets are all fun and games, just that not all external docker images support reading secrets from files. I do not want to modify for each of them and place a custom image. Might use them for my projects, yes, but for external projects would be a no go.
So that leaves env variables. But hey, they behave differently from compose to stack! Imagine my surprise when I noticed that they don't really work.
How is it possible to have docker stack without env support?best would be in my opinion --env-file=dev.env , so it wouldn't interfere with other env files... but the support for this is horrible. I must go back to k8s unfortunately, as the stack missing this from the start, could prove to be a horrible choice while in production, who knows how many other things will be missing.
It's been two years and we are still like that... I don't want to come across as rude, but come on! It's matter of reusing a bit of code from docker-compose!
Another similar problem I just ran in to is that even if you use env_file, the behavior is still not exactly the same.
I use env_file to load paths specified from the project root, but my compose file is in a different subdirectory. To launch with docker-compose, I just use --project-directory . -f path/to/docker-compose.yml
docker stack
does not allow me to specify the project-directory, causing all of my env_files to fail to load.
Changing env_file to "../../path/to/envrc" does not work with docker-compose, as these files must be inside the project root dir
+1
+1
+1 this would be really useful. Don't see a downside really.
It's incredibly dumb that docker doesn't support this yet.
+1 @joao-fidalgo It definitely is.
+1
Just ran into the same thing as we are trying out swarm. I've read through all of the messages in various threads and am left extremely frustrated. IMO, some really good points and strong arguments were made by @ntwrkguru and others. I hope we can consider them to get this feature in; hacks won't cut it.
.env file
export MYSQL_USER=user
source .env && docker stack deploy
It will also work with docker-compose up
for bash
.env file
export MYSQL_USER=user
source .env && docker stack deploy
It will also work with
docker-compose up
That would only work for bash and not other shells.
This confused me like crazy. My app would come up using docker-compose, but not with docker stack deploy. There should at least be a disclaimer prominently displayed in the docs
But IMO this is a bug, and is degrading the docker experience.
We need an answer about this
Nearly 2 years and no one has picked it up...don't hold your breath @jorgelimafeitosa
I don't think the CLI is ever going to add .env
support. The docker stack deploy
command was originally built with Distributed Application Bundle files in mind (hence the --bundle-file
option). DAB files were generated by Docker Compose with the docker-compose bundle
command. .env
and other Compose features would be handled by docker-compose
, before being passed to docker stack deploy
. Direct support for Compose files in docker stack deploy
was always more of a compromise.
The original promise of DAB files now lives on in Docker App, which also does not process .env
.
I have my developers use docker-compose config
to pre-process Docker Compose projects before passing them to docker stack deploy
. You can do this in one line with:
docker stack deploy -c <(docker-compose config) stack-name-here
That way, all Docker Compose features including .env
processing are fully applied.
@kinghuang Tried your solution, but didn't work. "docker-compose config" produces the correct output in the same directory, but "docker stack deploy -c docker-compose.yaml my_stack" will not substitute variables from the .env. What am I missing? This is Docker version 18.09.0, build 4d60db4.
@kinghuang Tried your solution, but didn't work. "docker-compose config" produces the correct output in the same directory, but "docker stack deploy -c docker-compose.yaml my_stack" will not substitute variables from the .env. What am I missing? This is Docker version 18.09.0, build 4d60db4.
docker stack deploy -c <(docker-compose -f docker-compose-frpc-swarm-traefik.yml config) traefik
@kinghuang
open /dev/fd/63: no such file or directory
WARNING: Some services (project1, project2) use the 'deploy' key, which will be ignored. Compose does not support 'deploy' configuration - use docker stack deploy
to deploy to a swarm.
@kinghuang
Only the root environment will not report an error.
Supporting .env
and env_file
doesn't always make sense in a deployment/production environment. You don't need direct access to the filesystem for any of the other features of Docker Swarm. So, a responsible designer/operator of that system would not want to give you the ability to dump environment files onto the filesystem.
Theoretically Swarm could support loading secrets into the environment automatically but see https://github.com/moby/moby/issues/30866#issuecomment-278924983 for why that might not be a good idea security-wise.
What you can do today is use secrets and load them into the environment of your app when the container runs. That gives you control over where the secret environment values can be seen.
+1
docker stack deploy should really support --env-file.
Myself I'm struggling with re-using the same .yml file to deploy different stacks for development/test/production environments and I don't want to deal with some fiddly export/sourcing of environment variables prior to deploying the stack. This is very error-prone (and a pain in the a** too to remember the exact commands each time).
In my particular case I e.g. want to set different index-names (elasticsearch) per environment - but the rest of the config stays the same. This has nothing to do with "secrets" as mentioned in earlier posts.
There seems to be a real need for --env-file for docker stack deploy based on the comment history above but sadly the Docker developers don't seem to see that.
In my swarm environment I settled on a few workarounds:
Just specify the .env file in your docker-compose.yml and it works:
env_file:
- .env
A work around in powershell to use on windows in order to parse the .env file before calling docker:
switch -regex -file "./.env" { "^\s([^#].+?)\s=\s(.)" { $name,$value = $matches[1..2]; Set-Item "env:$name" $value}}
Greatly inspired by parsing .ini files: https://stackoverflow.com/questions/417798/ini-file-parsing-in-powershell
Another workaround is: set -a && . .env && set +a && docker stack deploy...
.
This is ridiculous. I just spent all day trying to get this to work. A disclaimer is at least needed somewhere in the docs that .env is not read by docker stack
commands.
@cjancsar They do. The documentation says:
Important: The .env file feature only works when you use the docker-compose up command and does not work with docker stack deploy
Out of interest. What do people currently do when in swarm mode, and they want to update their newly built docker image from, e.g. application:v1 to application:v2, same service (nothing else changed)?
This is the reason I came to this issue. That is why I am interested.
Currently in docker-compose, it is trivial to get automation to interact with source-control untracked file . env
to update the image version, then docker-compose up -d
Often I use the commit sha as a docker image version for 'staging' deploys (git tags used for actual releases after sufficient testing cycles), so it isn't really possible to commit the new image version to source control.
Is it possible to update a docker secret (even though it isn't really a secret) as a workaround? Is that what people do, or is there something else that is done.
I am asking for future visitors of this issue, so that they actually come away with a current best practice, since the functionality they were looking for doesn't (yet?) exist.
Hi, I am busy looking into stack deploy for use for use in CI/CD pipelines, being able to use a .env file would be very useful, any feedback on if this option will be introduced at any stage?
It seems the official recommendation is, indeed, to migrate your image code to support reading these types of variables from a secrets text file ± retaining the ability to also read these from environmental variables for non-stack/swarm backwards compatibility.
The example uses one secret per text file, which avoids having to parse the old .env file.
Paraphrased from the documentation at https://docs.docker.com/engine/swarm/secrets/#use-secrets-in-compose :
services:
db:
image: mysql:latest
environment:
MYSQL_ROOT_PASSWORD_FILE: /run/secrets/db_root_password
MYSQL_DATABASE: wordpress
MYSQL_USER: wordpress
MYSQL_PASSWORD_FILE: /run/secrets/db_password
secrets:
- db_root_password
- db_password
secrets:
db_password:
file: db_password.txt
db_root_password:
file: db_root_password.txt
sigh
This should be more clear in the documentation. Although it's called out that .env is not supported in the Variable Substitution section per @lengxuehx, it is not mentioned that env_file is ignored for stack deploys.
I can confirm that solution proposed by @kinghuang works and does not exclude the deploy key like someone said.
docker stack deploy -c <(docker-compose config) stack-name-here
This should be more clear in the documentation. Although it's called out that .env is not supported in the Variable Substitution section per @lengxuehx, it is not mentioned that env_file is ignored for stack deploys.
I can confirm that env_file is used and working for deploy stack command, exactly as the docker compose does.
docker version
Client: Docker Engine - Community
Version: 19.03.4
API version: 1.40
Go version: go1.12.10
Git commit: 9013bf5
Built: Thu Oct 17 23:44:48 2019
OS/Arch: windows/amd64
Experimental: false
Server: Docker Engine - Community
Engine:
Version: 19.03.4
API version: 1.40 (minimum version 1.12)
Go version: go1.12.10
Git commit: 9013bf5
Built: Thu Oct 17 23:50:38 2019
OS/Arch: linux/amd64
Experimental: false
containerd:
Version: v1.2.10
GitCommit: b34a5c8af56e510852c35414db4c1f4fa6172339
runc:
Version: 1.0.0-rc8+dev
GitCommit: 3e425f80a8c931f88e6d94a8c831b9d5aa481657
docker-init:
Version: 0.18.0
GitCommit: fec3683
To summarize, for people like me, who have read this so far:
docker stack deploy
supports "Variable Substitution" but you need to set the environment variables from the .env
file in some way. Several options have been explained above. One of the neatest workarounds is using docker-compose config
as pre-processor.docker stack deploy -c <(docker-compose config) STACK_NAME
.env_file
parameter in thedocker-compose.yml
file will set the environment variables in the created container and not on the docker-compose.yml
file itself (and hence it cannot be used as an alternative to "Variable Substitution").I was corrected by @thaJeztah.
Docker does not support Variable Substitution using docker stack deploy, and non of the proposed solution do not work.
docker stack deploy
does support variable substitution, but does not evaluate the .env
file; in the example below, HELLO_VERSION
is set to linux
, and the service will use the hello-world:linux
tag (instead of the default hello-world:latest
)
HELLO_VERSION=linux docker stack deploy -c docker-compose.yml mystack
Creating network mystack_default
Creating service mystack_hello
docker service inspect --format '{{.Spec.TaskTemplate.ContainerSpec.Image}}' mystack_hello
hello-world:linux@sha256:d073a5775c0b99d653c413161a8ed0e9685061afe697931d30eddf6afeef40f6
That being said, you still can use environment variables using env_file parameter in your docker-compose.yml file
The env_file
serves a different purpose (and is the equivalent of docker run --env-file
); the env_file
option specifies what env-vars to set on the container that's created, but is not used in the compose file itself (and not used for substituting variables in the compose file before deploying the stack).
I had the same problem along other slight differences between docker-compose and docker stack.
I ended up creating https://github.com/egyel/dcsh script/tool to handle this issue with pipes.
Hello everyone, this helped me put env_file in my docker-compose:
env_file: /path/to/env/file
not
env_file:
- /path/to/env/file
i just saw this from another post and I can only speculate why it works (same as your speculation) but we need confirmation as to why this is working as docker explicitly mentioned in the docu that env_file doesnt work.
My understanding is that env files can't be used to fiill placeholders in
the docker-stack.yml file but they can still be provided to containers.
Note that what you are doing doesn't allow you to set the image name from
the env file for example.
On Sun, May 17, 2020, 06:08 raphyphy notifications@github.com wrote:
[image: image]
https://user-images.githubusercontent.com/30310576/82135555-a1e4be00-9836-11ea-9df4-a1b82e014b0e.png
Hello everyone, this helped me put env_file in my docker-compose:env_file: /path/to/env/file
notenv_file:
- /path/to/env/file
i just saw this from another post and I can only speculate why it works
(same as your speculation) but we need confirmation as to why this is
working as docker explicitly mentioned in the docu that env_file doesnt
work.—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub
https://github.com/moby/moby/issues/29133#issuecomment-629740002, or
unsubscribe
https://github.com/notifications/unsubscribe-auth/ABHLQMCARDQGJQIBWCQKAYLRR5PMHANCNFSM4CYRHCTA
.
The docker-compose solution mentioned above:
docker stack deploy -c <(docker-compose config) stack-name-here
has the disadvantage (for me) that things like .env
files and, especially, docker-compose.override.yml
files are normally more part of my development environment. I don't really want those brought in when deploying to production.
I ended up having a separate docker-compose-production.yml
in which I controlled things carefully, even though that involved some duplication.
I don't think the CLI is ever going to add
.env
support. Thedocker stack deploy
command was originally built with Distributed Application Bundle files in mind (hence the--bundle-file
option). DAB files were generated by Docker Compose with thedocker-compose bundle
command..env
and other Compose features would be handled bydocker-compose
, before being passed todocker stack deploy
. Direct support for Compose files indocker stack deploy
was always more of a compromise.The original promise of DAB files now lives on in Docker App, which also does not process
.env
.I have my developers use
docker-compose config
to pre-process Docker Compose projects before passing them todocker stack deploy
. You can do this in one line with:docker stack deploy -c <(docker-compose config) stack-name-here
That way, all Docker Compose features including
.env
processing are fully applied.
This works like a charm, keep in mind if your compose file does not have the "docker-compose.yml" name your command should include the actual compose file name.
docker stack deploy -c <(docker-compose -f CUSTOM-COMPOSE-FILENAME.yml config) CUSTOM-STACK
BEWARE of the <(docker-compose -f CUSTOM-COMPOSE-FILENAME.yml config
HACK!!! The output of docker-compose config
and docker-compose -f myfile.yml config
is NOT necessarily the same! The latter sometimes wraps env variables in extra quotes, so the output will be wrong!
Example:
environment:
SERVER_URL: '"xxx"'
instead of
environment:
SERVER_URL: xxx
Is this issue tracked somewhere already?
Most helpful comment
@whoan I'm using this as a workaround:
That way, variables don't get stuck on the terminal window