Moby: `docker stack deploy` na versão 1.13 não carrega o arquivo `.env` como `docker-compose up`

Criado em 5 dez. 2016  ·  93Comentários  ·  Fonte: moby/moby

Para testar a função docker stack deploy --compose-file , carrego uma das minhas amostras 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:

Na seção image do serviço nginx e php , usei ${DOCKER_USER} para obter o ID do docker das variáveis ​​de ambiente. E se eu usar docker-compose up , ele carregará o arquivo .env como arquivos envvar padrão, cujo conteúdo é:

DOCKER_USER=twang2218

No entanto, se eu usar docker stack para implantar este docker-compose.yml , terei os seguintes erros:

$ 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

Como você pode ver, como o comando docker stack deploy não carregou o arquivo .env , o ${DOCKER_USER} foi substituído por uma string vazia, o que faz com que o nome da imagem se torne inválido.

Se o arquivo .env foi carregado, o nome da imagem final deve ser twang2218/lnmp-php:v1.2 .

A substituição de ambiente está realmente funcionando, se eu executar o comando desta forma:

$ 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

E podemos verificar se está funcionando pelo comando docker service inspect :

$ docker service inspect lnmp_php | grep Image
                    "Image": "twang2218/lnmp-php:v1.2<strong i="13">@sha256</strong>:4f1aef1350aeef3f757f6b6da8f2e1a79ff849f61382320e4b668bfe2b0d1c5a",

O nome da imagem é twang2218/lnmp-php:v1.2 , o que está correto.

Testei esse recurso no droplet Digitial Ocean, que instalou o docker 1.13.0-rc2 via docker-machine .

Aqui está a versão:

$ 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

Aqui está o docker info :

root<strong i="25">@d1</strong>:~/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
arestack areswarm kinenhancement

Comentários muito úteis

@whoan estou usando isso como solução alternativa:

env $(cat .env | grep ^[A-Z] | xargs) docker stack deploy --compose-file docker-compose.yml [STACK_NAME]

Dessa forma, as variáveis ​​não ficam presas na janela do terminal

Todos 93 comentários

Isso é por design. O suporte .env é um recurso do Compose, não do formato do arquivo.

Podemos discutir a adição disso para uma versão futura, mas não sei se é realmente a melhor opção.

O suporte .env é bastante útil no Compose, nós o usamos em muitos de nossos arquivos de composição. Ele separa partes dinâmicas e partes estáticas do arquivo docker-compose.yml . Com load .env por padrão, podemos apenas fornecer diferentes arquivos .env para diferentes ambientes e manter o docker-compose.yml e os scripts relacionados estáticos.

Não é possível usar env_file ou environment em docker-compose.yml para obter o mesmo resultado de substituição de envvars. .env é a maneira mais fácil de fazer isso.

Caso contrário, temos que prefixar export em cada linha do arquivo .env e manualmente source .env toda vez antes de carregar o docker-compose.yml , e as etapas extras às vezes são propensas Errar.

Acabei de notar isso.
Eu assumi/esperava que funcionasse da mesma maneira que para Compose, mas não é o caso de docker deploy .

No meu caso particular, eu esperava usar o arquivo .env para armazenar dados confidenciais (senhas, chaves de API, etc) usados ​​nos serviços que criarei na pilha:

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

Enquanto este arquivo Compose será verificado no Git, o arquivo .env será ignorado.

Eu acompanhei todo o material/histórico dos arquivos *.dab vs compose, e sinto que vocês estão tentando evitar algo - ou propondo uma solução melhor - mas perdi a noção de toda a discussão...

Olá a todos,

Versão do Docker: v1.13.0-rc4

Estou recebendo o erro: Ignorando opções não suportadas: build , isso significa que não criará a compilação do Dockerfile?

E também recebendo o mesmo erro para network_mode: Ignoring unsupported options: network_mode.

Abaixo está o comando:
DOCKER_IMAGE=akhil123 docker stack deploy -c docker-compose.yml foo

Muito obrigado antecipadamente.

@akhildangore , por favor, não comente sobre questões que não estejam diretamente relacionadas. O recurso docker stack deploy , _by design_ não executa compilações. A razão para isso é que um _build_ é executado no host do qual o comando é executado, portanto, a imagem estará disponível apenas no nó _that_. Ao implantar essa imagem em um Swarm, o serviço não pode ser iniciado em outros nós. Para implantar serviços, certifique-se de que a imagem que você está implantando seja enviada para um registro (ou para teste; verifique se a imagem está disponível em todos os nós do enxame)

Existem casos/discussões a favor/contra apoiar este comportamento em docker deploy ?

@vovimayhem nenhuma decisão foi tomada ainda no arquivo .env , mas você pode estar interessado em https://github.com/docker/docker/pull/30144 , que adiciona suporte para segredos ao arquivo de composição

Acabei de encontrar essa discussão. Excelente!

Estou usando uma função bash como solução alternativa.

Você pode adaptá-lo às suas necessidades até que o recurso secrets seja lançado:

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
    )
}

Para os assinantes desta edição; o suporte a segredos para arquivos docker-compose será incluído na versão 1.13.1, que não deve demorar muito no futuro

@whoan estou usando isso como solução alternativa:

env $(cat .env | grep ^[A-Z] | xargs) docker stack deploy --compose-file docker-compose.yml [STACK_NAME]

Dessa forma, as variáveis ​​não ficam presas na janela do terminal

É sempre bom ter a capacidade de carregar coisas de um arquivo .env - além de um caso de uso de segredos do Docker mais simples que agora pode ser contornado, sempre há valores do Docker Compose que você não deseja ter codificados em seu repositório.

Vamos supor que você use docker stack deploy para implantar uma pilha completa e tenha os seguintes requisitos:

  • você deseja usar exatamente a mesma configuração para ambientes diferentes - por exemplo, preparação e produção

    • você precisa ter valores de escala diferentes para cada ambiente

Se você não puder configurar isso com um arquivo .env , precisará alterar manualmente o arquivo docker-compose.yml antes de implantar a pilha a cada vez, caso contrário, o valor da escala de serviço será revertido para 1.

Você pode estender o acima com coisas como redes, configurar o DNS que um serviço deve ouvir, etc.

Eu posso redigir um PR que carregará um arquivo .env , se existir um no mesmo diretório que docker-compose.yml se acreditarmos que os casos de uso acima fazem sentido.

O design do deploy docker stack é um pouco diferente dos comandos docker-compose . Eu não acho que faça sentido apenas ler um .env por padrão. Nem mesmo o docker-compse.yml é lido por padrão, porque no futuro a fonte de implantação padrão provavelmente será outra.

Você sempre pode obter um arquivo .env antes de executar stack deploy .

Apenas . .env antes de chamar docker stack deploy não ajuda, $variáveis ​​não são substituídas. Apenas env .. xargs o truque ajudou.
Seria bom ter a opção --env-file=FILE como em docker run .

Somente . .env antes de chamar o docker stack deploy não ajuda

Isso deve ajudar @C-Pro - você precisa ter export ... linhas em seu arquivo .env . Alternativamente, você pode fazer export $(cat .env) , o que funcionaria para a maioria dos casos.

Olá a todos,
Hoje eu tentei correr docker stack deploy .
Meu arquivo docker-compose.yml :

version: '3'
services:
  simple:
    image: alpine
    environment:
      - FOO: ${BAR}
    env_file: .env

E o arquivo .env no mesmo diretório:

BAR=worked

Após o lançamento docker stack deploy -c docker-compose.yml test , inspecionei o container e obtive isto:

$ env
BAR=worked
FOO=
...

Parece que, .env fornecido no contêiner, mas não fornecido na máquina host.
Isso significa que eu posso usar o arquivo .env em vez da seção environment , mas não posso usar o arquivo .env com Substituição de Variável.
Versão do Docker: v17.03

@ddpaimon
ambiente:
- FOO=${BAR}

Parece que o arquivo .env funciona apenas para o contêiner, mas não para a substituição da variável do arquivo docker-compose.yml.

Docker para MAC, versão do Docker 17.03.1-ce, compilação c6d412e

@realcbb
sim. Mas para usar variáveis ​​de arquivo .env dentro do container, você deve removê-las na seção environment .
Por exemplo:
docker-compose.yml

...
environment:
  - FOO=${FOO:-empty}
...

.env

FOO=filled

No container eu consegui isso:

$ env
FOO=empty

Mas se eu remover FOO da seção environment em docker-compose.yml , eu tenho isso:

$ env
FOO=filled

@ddpaimon
As variáveis ​​de ambiente especificadas em ambiente substituem esses valores especificados no arquivo .env.

@dnephin : você afirma que .env não faz parte do formato de arquivo de composição do docker. No entanto, o recurso de arquivo .env está documentado na referência do arquivo Compose versão 3: https://docs.docker.com/compose/compose-file/#variable -substitution .
Isso dá a impressão de que .env também deve funcionar com a implantação da pilha do docker.
Além disso, como já mencionado por outros, separar valores específicos do ambiente real da definição de pilha yaml é um recurso muito desejado/necessário. Especificamente, queremos usá-lo para especificar versões e replicações de imagens.

Obrigado, abri https://github.com/docker/docker.github.io/issues/3654 para corrigir os documentos

docker stack deploy pode receber um arquivo gerado. Isso funciona no bash para todas as minhas variáveis ​​e também mantém segredos em segredo:

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

Observe que adicionei as variáveis ​​ENV em linha como adicionais ou substituições. Meus arquivos de composição fazem referência a arquivos .env e isso funciona. Espero que seja útil 👍

A funcionalidade de docker-compose config é o que une isso.

Me deparei com esse problema ao procurar uma solução para o meu .env não ser lido por docker stack deploy . Fiquei um pouco surpreso ao ver que não era suportado (os documentos podem ser esclarecidos), mas quero adicionar meu suporte para .env , como compose.

Meu caso de uso é que eu uso docker stack deploy em ambientes dev, test, staging e uso variáveis ​​de ambiente para opções de pilha para manter o arquivo yml o mesmo.

Atualmente usando uma das soluções postadas aqui, mas usando um arquivo .env seria a rota preferida.

Apenas um lembrete amigável: pode haver a possibilidade de você estar tentando usar arquivos dotenv para armazenar chaves de API, senhas e outras coisas consideradas "sensíveis" para colocar no cluster. Para esses casos, você deve usar o Docker Secrets .

Para outras coisas, posso sugerir ter um arquivo de composição por ambiente implantado/implantável? A maioria das coisas que mudam entre os diferentes ambientes serão os servidores disponíveis, a organização do servidor diferente, etc... e, portanto, precisando de valores diferentes nos conteúdos da chave deploy ( placement resources reservas, etc), tornando o uso de um único arquivo para tudo um pouco complicado demais.

Na verdade, eu quero esse recurso, as variáveis ​​no arquivo de composição podem ser tratadas como valores diferentes em um host diferente ao usar a implantação da pilha do docker.

"Para outras coisas, posso sugerir ter um arquivo de composição por ambiente implantado/implantável? A maioria das coisas que mudam entre diferentes ambientes serão os servidores disponíveis, organização de servidor diferente, etc... e, portanto, precisando de valores diferentes na chave de implantação conteúdos (regras de posicionamento, reservas de recursos, etc), tornando o uso de um único arquivo para tudo um pouco complicado demais."

@vovimayhem Desculpe ser franco, mas isso não faz tanto sentido quanto usar um único arquivo de composição com substituição de variável usando um env_file. Prefiro usar o formato env_file, pois isso também torna muito mais fácil fornecer pilhas como uma entrega para meus clientes e treiná-los para atualizar um único arquivo vars no estilo ini do que mexer com um arquivo de composição (o que eu NÃO não quero).

As configurações de serviço são uma ótima adição, mas não parecem utilizáveis ​​para interpolação de tempo de implantação (por exemplo, $TAG).

Se as variáveis ​​de ambiente forem suportadas, seja consistente nos mecanismos usados ​​para resolvê-las nas ferramentas. A implantação de pilha parece escolher ser inconsistente, sem alterar fundamentalmente os comportamentos das variáveis ​​de ambiente. Segredos e configurações de serviço são alternativas melhores para alguns usos de variáveis ​​de ambiente, mas eles não são incluídos.

Você não parece entender @vovimayhem. Não estou falando sobre passar envs para containers; que funciona como esperado. O que quero dizer é usar um env_file que é analisado durante stack deploy como era durante compose up .

@ntwrkguru Achei que esse novo recurso ajudaria você... Estou tão triste que não.

Isso ainda funciona como uma alternativa;

$ 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 , de fato, sim. Eu tenho uma tarefa no meu playbook para criar um arquivo de ambientes, mas isso está faltando ao ponto maior. Isso costumava ser possível com compose e agora não é possível com stack . IMO, isso é uma regressão. Além disso, em seu exemplo, você ainda está passando uma variável de ambiente para o contêiner. Eu posso fazer isso com o env_files hoje; o problema é analisar o env_file durante a operação stack deploy -c docker-compose.yml .

Isso é especialmente doloroso, pois stack não suporta mais vários arquivos de composição, caso contrário, pode-se simplesmente usar um arquivo de composição secundário por ambiente. Para fazê-lo dessa maneira, é necessário construir o arquivo de pilha a partir dos arquivos de composição, introduzindo outra etapa. Então, de qualquer forma, passamos de um processo de uma única etapa para um processo de várias etapas para obter o mesmo resultado final.

Além disso, FWIW, o configs é realmente inferior na minha experiência para configurações reais. Eu estava imaginando (esperando) que eu pudesse ter /application/config.conf na fonte. Atualizar esse arquivo, confirmar, enviar e CI reimplantará a pilha com a nova configuração. Isso não é possível sem algum hacker para alterar o nome do arquivo ou algum outro mecanismo. Certamente podemos somar o arquivo, no mínimo, ou verificar alterações de conteúdo e atualizar com base no próprio arquivo? Em suma, parece que estamos indo para trás. Acrescente o suporte para K8s agora e isso me faz pensar se o enxame vai apenas definhar na videira até perder o uso o suficiente para cair silenciosamente.

Além disso, FWIW, as configurações são realmente inferiores na minha experiência para configurações reais. Eu estava imaginando (esperando) que eu pudesse ter /application/config.conf na fonte. Atualizar esse arquivo, confirmar, enviar e CI reimplantará a pilha com a nova configuração. Isso não é possível sem algum hacker para alterar o nome do arquivo ou algum outro mecanismo.

@ntwrkguru A solução simples é alterar não o nome do arquivo, mas o nome da própria configuração. Eu empreguei um esquema de versão para meus nomes de configuração, por exemplo config_v1 , config_v2 , ..

Então lembre-se de atualizar essa versão depois de alterar o arquivo de configuração.

services:
  app:
    [...]
    configs:
      - source: config_v2
      - target: /config.yml

configs:
  config_v2:
    file: ./config.yml

Eu entendo o raciocínio por trás de não ter configurações e segredos com versão ainda, então, pessoalmente, atualmente estou bem com essa solução (fácil).

Obrigado @djmaze , mas isso é uma coisa ridícula de se fazer quando há rastreamento de versão inerente embutido em cada sistema de controle de origem. Além disso, obrigado pelo link; Comentei lá também. Não vejo por que o Docker se preocupa com a versão diferente da atual. A única razão pela qual eu pude ver a necessidade de versão destes é para reversão, mas toneladas de coisas precisam ser rastreadas lá também, então o que há mais? (diz o cara que não precisa escrever o código) :-)

Tente isto:
echo "$(docker-compose -f stack.yml config 2>/dev/null)" | docker stack deploy -c- stack_name

Ele usa o docker-compose para analisar o arquivo de configuração, substituindo env vars, remove os avisos da saída e, em seguida, o canaliza para o docker stack deploy via stdin.
Substitua '-f stack.yml' pelo nome do seu arquivo de configuração ou omita-o para usar o docker-compose.yml padrão.

+1

Um ano depois e ainda temos que hackear isso para funcionar. A partir de 17.09.1, docker stack deploy -f compose.yml nem substituirá usando vars de shell conhecidos.

$ 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

Quaisquer variáveis ​​para tags produzirão invalid reference format .

Um ano depois e ainda temos que hackear isso para funcionar. A partir de 17.09.1, o docker stack deploy -f compose.yml nem substituirá o uso de vars de shell conhecidos.

veja Como manter variáveis ​​de ambiente ao usar 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   

Obrigado, mas alguma palavra sobre simplesmente apoiar a substituição de variáveis ​​de um arquivo?

[editar] Isso não deve ser um problema (mas pode ser), pois estou usando o Ansible para executar a tarefa com become: yes , mas o usuário ainda é o mesmo usuário que origina o ambiente vars.

Não posso acreditar que isso não seja possível. Gostaríamos de manter um único arquivo de pilha e poder alterar as opções de implantação usando variáveis ​​dinâmicas.

Isso funcionaria, mas é feio e um hack:

echo "$(docker-compose -f stack.yml config 2>/dev/null)" | docker stack deploy -c- stack_name

Estou mexendo com isso há muitas horas e parece que estou fazendo algum trabalho de script em segundo plano (estarei usando CI para fazer isso) para criar um arquivo DAB a partir dessas várias peças. Seria bom ter uma ferramenta docker que fizesse isso... :-) Talvez adicionar um --env-file version.env adicionado a docker-compose bundle ?

No meu caso de uso, quero usar um "manifesto" version.env para rastrear e controlar as versões de contêineres/imagens que compõem uma plataforma. Meu processo está assim:

  • Atualizar arquivo .env
  • Arquivo de origem .env para preencher as vars do shell
  • Correr docker-compose -f stack.yml config > docker-compose.yml
  • Execute docker-compose pull para registrar os resumos da imagem
  • Executar arquivo DAB docker-compose bundle -o stack.version.dab

Neste ponto, idealmente eu seria capaz de docker deploy --host manager.swarm.com --bundle-file stack.version.dab --with-registry-auth --resolve-image always stack-name , mas entendo que não é possível agora. Nesse caso, eu faria o scp do arquivo DAB para o gerente e executaria o docker deploy .

Esse é o fluxo de trabalho que o Docker tinha em mente @thaJeztah? Existe uma maneira melhor?

[editar] Isso não funciona porque um DAB ignora as diretivas volume: , network: e deploy: . Eu passei a simplesmente fornecer um arquivo env para o shell, reconstruir um arquivo de composição temporário e, em seguida, implantá-lo.

Eu adoraria que os arquivos .env fossem lidos por padrão como no Docker Compose e --env-file (short -e ) fossem adicionados para docker stack deploy para poder substituir variáveis ​​de ambiente e os padrões do arquivo .env .

+1
Seria bastante conveniente ler o .env em primeiro lugar como o docker-compose faz.
Por padrão ou apenas passe o arquivo env como parâmetro na linha de comando da pilha do docker.

As duas soluções já mencionadas (_encontre-as também abaixo_) parecem funcionar, embora um pouco feias em comparação com a 'correção' proposta.

_echo "$(docker-compose -f stack.yml config 2>/dev/null)" | implantação de pilha do docker -c- stack_name_

_env $(cat .env | grep ^[AZ] | xargs) docker stack deploy --compose-file docker-compose.yml [STACK_NAME]_

Eu acrescentaria que ter o docker-compose instalado apenas para poder processar essas variáveis ​​também pode ser bastante perigoso, na verdade.

Se alguém implantar a pilha usando docker-compose up -d por engano em vez de usar o docker stack deploy, isso provavelmente induziria erros de aplicativos e corrupção de arquivos.

Ter a interpolação de variáveis ​​de ambiente na implantação é a melhor solução para integração contínua.

Um problema com o uso de '.env' é que ele se sobrepõe a nomes de arquivos semelhantes usados ​​por, por exemplo, Ruby on Rails, ter a capacidade de especificar um arquivo de ambiente por argumento é superior.

As sugestões de @ntelisil são bem aceitas, podem ser complementadas ou modificadas por:

https://unix.stackexchange.com/questions/294835/replace-environment-variables-in-a-file-with-their-actual-values :

Você pode usar envsubst (parte do gnu gettext):
envsubst < arquivo

Eu usei:

$ envsubst < docker-compose.yml-template > docker-compose.yml

E isso funcionou bem, mas eu precisava adicionar 3Mb ou mais ao meu contêiner.

Legal @rnickle , mas ainda "hacky" comparado ao Docker ser capaz de fazer isso do jeito que costumava fazer. Parece (e, por favor, os caras do Docker me corrijam se eu estiver errado) que há muito pouco esforço no modo swarm desde o anúncio do suporte ao K8s, então duvido que qualquer uma dessas regressões seja abordada.

E isso funcionou bem, mas eu precisava adicionar 3Mb ou mais ao meu contêiner.

Se as variáveis ​​de ambiente estiverem definidas, docker slack deploy já deve interpolá-las

comparado ao Docker ser capaz de fazer isso do jeito que costumava fazer.

O Docker nunca teve esse recurso; docker compose tinha; docker compose e docker stack deploy compartilham o _formato de arquivo_ mas não necessariamente todos os comportamentos do próprio software.

que há muito pouco esforço para entrar no modo de enxame desde o anúncio do suporte ao K8s

A manipulação de arquivos de composição é feita no lado do cliente e usada tanto para k8s quanto para swarmkit, portanto, nada diminui a velocidade nesta área, além de "há muito o que podemos fazer a qualquer momento"

Para aqueles que esperam por esse recurso; a próxima versão terá suporte para vários arquivos de composição para docker stack deploy , portanto, se você estiver usando esse recurso no docker compose: a próxima versão do docker também suportará isso

Semântica à parte, obrigado pela atualização. Quando digo Docker, não me refiro necessariamente ao daemon ou mecanismo, mas à empresa que constrói as ferramentas. A gênese para o comentário sobre haver pouco esforço realmente decorre do fato de que o modo swarm foi lançado há mais de um ano e ainda está muito atrás de onde estávamos com um único nó usando composição.

Eu posso apreciar que eles são diferentes, mas usam o mesmo formato de arquivo, mas isso realmente leva a mais confusão e potencialmente decepcionante, quando os usuários descobrem que precisam trocar recursos pelo uso de enxame. Isso e o fato de que os arquivos DAB AINDA estão sendo listados como experimentais. Infelizmente, tomamos a decisão de usar o modo enxame em um grande projeto, ou eu nem me importaria. Felizmente, não cometeremos esse erro novamente.

[editar]

Se as variáveis ​​de ambiente estiverem definidas, o docker slack deploy já deve interpolá-las

Fazer isso em um ambiente de CI é uma dor de cabeça real. Essencialmente, acabei instalando o compose, obtendo os envvars, lavando o arquivo de composição (depois de extrair as imagens) e, em seguida, cuspindo um novo arquivo de composição para uso com stack deploy . (E eu nem vou começar a falar como é doloroso quando :latest não significa :latest no modo de enxame, já que esse problema é especificamente sobre interpolação de variáveis.)

_EDIT: Espero que este post não seja agressivo. Eu amo o conceito do Docker Stack e acho que toda a suíte Docker é muito bem suportada. Parece que o Docker (a organização) atualmente não vê seus produtos da mesma maneira que os usuários, o que é lamentável e parece ser a causa da maioria dos problemas que encontrei ao usar Compose e Stack._

O Docker nunca teve esse recurso; docker compose tinha; docker compose e docker stack deploy compartilham o formato do arquivo, mas não necessariamente todos os comportamentos do próprio software.

Sinto que essa declaração revela uma desconexão fundamental entre a maneira como os desenvolvedores e usuários do Docker veem esses produtos. Como usuário, esteja trabalhando com o Docker Engine, Docker Compose ou Docker Swarm, tudo é Docker e deve se comportar de forma consistente o máximo possível.

Minha compreensão do propósito desses produtos é:

  • O Docker Engine é para construir e executar contêineres individuais
  • O Docker Compose é para executar um conjunto de contêineres em desenvolvimento
  • O Docker Stack é para implantar contêineres na produção

Um dos principais pontos de venda do Docker (e dos contêineres em geral) é a fácil reutilização do mesmo aplicativo em vários ambientes. Portanto, a composição deve ser aditiva ao mecanismo e a pilha deve ser aditiva à composição. Particularmente porque eles compartilham o mesmo formato de arquivo, o Stack não suporta recursos do Compose leva à confusão para os desenvolvedores e aumenta a complexidade nos processos de CI.

Eu não diria que compose é para dev e stack para prod, necessariamente. Eu vejo compose como sendo para um aplicativo de vários contêineres ou "sistema" e empilhamento para implantações de vários hosts usando o modo swarm como o agendador/orquestrador. Caso contrário, seu comentário está 100% correto. Também estou frustrado (se não fosse óbvio pelos meus outros comentários) que há uma desconexão entre os desenvolvedores e os usuários sobre como os produtos estão sendo usados.

uau. Juntei-me à confusão e à dor ao avaliar o enxame do docker para um grande projeto também.
Os segredos são divertidos e divertidos, só que nem todas as imagens externas do docker suportam a leitura de segredos de arquivos. Não quero modificar para cada um deles e colocar uma imagem personalizada. Poderia usá-los para meus projetos, sim, mas para projetos externos seria impossível.
Então isso deixa variáveis ​​​​env. Mas ei, eles se comportam de maneira diferente de compor para empilhar! Imagine minha surpresa quando notei que eles realmente não funcionam.
Como é possível ter docker stack sem suporte a env?melhor seria na minha opinião --env-file=dev.env , para não interferir com outros arquivos env... mas o suporte para isso é horrível. Infelizmente, devo voltar ao k8s, pois a pilha que faltava isso desde o início pode ser uma escolha horrível enquanto estiver em produção, quem sabe quantas outras coisas estarão faltando.

Já se passaram dois anos e ainda estamos assim... Não quero parecer rude, mas vamos lá! É questão de reutilizar um pouco de código do docker-compose!

Outro problema semelhante que acabei de encontrar é que, mesmo se você usar env_file, o comportamento ainda não é exatamente o mesmo.

Eu uso env_file para carregar caminhos especificados na raiz do projeto, mas meu arquivo de composição está em um subdiretório diferente. Para iniciar com docker-compose, apenas uso --project-directory . -f path/to/docker-compose.yml

docker stack não me permite especificar o diretório do projeto, fazendo com que todos os meus env_files falhem ao carregar.

Alterar env_file para "../../path/to/envrc" não funciona com docker-compose, pois esses arquivos devem estar dentro do diretório raiz do projeto

+1

+1

+1 isso seria muito útil. Não vejo uma desvantagem realmente.

É incrivelmente estúpido que o docker ainda não suporte isso.

+1 @joao-fidalgo Com certeza é.

+1

Acabei de encontrar a mesma coisa que estamos experimentando o enxame. Eu li todas as mensagens em vários tópicos e fiquei extremamente frustrado. IMO, alguns pontos realmente bons e argumentos fortes foram feitos por @ntwrkuru e outros. Espero que possamos considerá-los para obter esse recurso; hacks não vão cortá-lo.

arquivo .env

export MYSQL_USER=user

source .env && docker stack deploy

Também funcionará com docker-compose up para bash

arquivo .env

export MYSQL_USER=user

source .env && docker stack deploy

Também funcionará com docker-compose up

Isso só funcionaria para o bash e não para outros shells.

Isso me confundiu como um louco. Meu aplicativo apareceria usando o docker-compose, mas não com o docker stack deploy. Deve haver pelo menos um aviso de isenção de responsabilidade exibido com destaque nos documentos

Mas IMO isso é um bug e está degradando a experiência do docker.

Precisamos de uma resposta sobre isso

Quase 2 anos e ninguém pegou... não prenda a respiração @jorgelimafeitosa

Eu não acho que a CLI vai adicionar suporte .env . O comando docker stack deploy foi originalmente criado com os arquivos Distributed Application Bundle em mente (daí a opção --bundle-file ). Os arquivos DAB foram gerados pelo Docker Compose com o comando docker-compose bundle . .env e outros recursos do Compose seriam tratados por docker-compose , antes de serem passados ​​para docker stack deploy . O suporte direto para arquivos Compose em docker stack deploy sempre foi mais um compromisso.

A promessa original de arquivos DAB agora vive no Docker App, que também não processa .env .

Meus desenvolvedores usam docker-compose config para pré-processar projetos do Docker Compose antes de passá-los para docker stack deploy . Você pode fazer isso em uma linha com:

docker stack deploy -c <(docker-compose config) stack-name-here

Dessa forma, todos os recursos do Docker Compose, incluindo o processamento .env , são totalmente aplicados.

@kinghuang Tentei sua solução, mas não funcionou. "docker-compose config" produz a saída correta no mesmo diretório, mas "docker stack deploy -c docker-compose.yaml my_stack" não substituirá as variáveis ​​do .env. o que estou perdendo? Esta é a versão 18.09.0 do Docker, compilação 4d60db4.

@kinghuang Tentei sua solução, mas não funcionou. "docker-compose config" produz a saída correta no mesmo diretório, mas "docker stack deploy -c docker-compose.yaml my_stack" não substituirá as variáveis ​​do .env. o que estou perdendo? Esta é a versão 18.09.0 do Docker, compilação 4d60db4.

docker stack deploy -c <(docker-compose -f docker-compose-frpc-swarm-traefik.yml config) traefik

@kinghuang

abra /dev/fd/63: nenhum arquivo ou diretório

AVISO: Alguns serviços (project1, project2) usam a chave 'deploy', que será ignorada. O Compose não oferece suporte à configuração de 'implantação' - use docker stack deploy para implantar em um enxame.

@kinghuang
Apenas o ambiente raiz não relatará um erro.

O suporte .env e env_file nem sempre faz sentido em um ambiente de implantação/produção. Você não precisa de acesso direto ao sistema de arquivos para nenhum dos outros recursos do Docker Swarm. Portanto, um designer/operador responsável desse sistema não gostaria de dar a você a capacidade de despejar arquivos de ambiente no sistema de arquivos.

Teoricamente, o Swarm poderia suportar o carregamento de segredos no ambiente automaticamente, mas consulte https://github.com/moby/moby/issues/30866#issuecomment -278924983 para saber por que isso pode não ser uma boa ideia em termos de segurança.

O que você pode fazer hoje é usar segredos e carregá-los no ambiente do seu aplicativo quando o contêiner for executado. Isso lhe dá controle sobre onde os valores do ambiente secreto podem ser vistos.

+1
A implantação da pilha do docker deve realmente suportar --env-file.
Eu mesmo estou lutando para reutilizar o mesmo arquivo .yml para implantar pilhas diferentes para ambientes de desenvolvimento/teste/produção e não quero lidar com algumas exportações/fontes complicadas de variáveis ​​de ambiente antes de implantar a pilha. Isso é muito propenso a erros (e uma dor de cabeça também para lembrar os comandos exatos a cada vez).
No meu caso particular, por exemplo, quero definir nomes de índice diferentes (elasticsearch) por ambiente - mas o restante da configuração permanece o mesmo. Isso não tem nada a ver com "segredos" como mencionado em posts anteriores.
Parece haver uma necessidade real de --env-file para implantação da pilha do docker com base no histórico de comentários acima, mas infelizmente os desenvolvedores do Docker não parecem ver isso.

No meu ambiente de enxame, decidi algumas soluções alternativas:

  • secrets/configs, que estou usando para carregar arquivos de configuração e certificados.
  • Depois de assistir a uma demonstração do ambiente de desenvolvimento do Azure, onde eles tinham um script de interpolação variável que executavam antes de enviar um arquivo de composição, escrevi o meu próprio, que coloquei no meu fluxo de lançamento do GitLab.

Basta especificar o arquivo .env em seu docker-compose.yml e funciona:

env_file:
  - .env

Consulte https://stackoverflow.com/questions/44694640/docker-swarm-with-image-versions-externalized-to-env-file

Uma solução alternativa no powershell para usar no Windows para analisar o arquivo .env antes de chamar o docker:

switch -regex -file "./.env" { "^\s ([^#].+?)\s =\s (. )" { $name,$value = $matches[1..2]; Set-Item "env:$name" $value}}

Muito inspirado pela análise de arquivos .ini: https://stackoverflow.com/questions/417798/ini-file-parsing-in-powershell

Outra solução alternativa é: set -a && . .env && set +a && docker stack deploy... .

Isto é ridículo. Passei o dia todo tentando fazer isso funcionar. Um aviso é pelo menos necessário em algum lugar nos documentos que .env não é lido por comandos docker stack .

@cjancsar Eles fazem. A documentação diz:

Importante: o recurso de arquivo .env só funciona quando você usa o comando docker-compose up e não funciona com a implantação da pilha do docker

Fora de interesse. O que as pessoas fazem atualmente quando estão no modo swarm e desejam atualizar sua imagem do docker recém-criada de, por exemplo, application:v1 para application:v2 , mesmo serviço (nada mais alterado)?

Esta é a razão pela qual eu vim para esta questão. Por isso estou interessado.

Atualmente no docker-compose, é trivial obter a automação para interagir com o arquivo não rastreado de controle de origem . env para atualizar a versão da imagem e, em seguida, docker-compose up -d

Muitas vezes eu uso o commit sha como uma versão de imagem do docker para implantações de 'staging' (tags git usadas para lançamentos reais após ciclos de teste suficientes), portanto, não é realmente possível confirmar a nova versão da imagem no controle de origem.

É possível atualizar um segredo do docker (mesmo que não seja realmente um segredo) como solução alternativa? É isso que as pessoas fazem, ou há algo mais que é feito.

Estou pedindo aos futuros visitantes desta edição, para que eles realmente saiam com uma prática recomendada atual, já que a funcionalidade que eles estavam procurando (ainda?) não existe.

Oi, estou ocupado olhando para implantação de pilha para uso em pipelines CI/CD, poder usar um arquivo .env seria muito útil, algum feedback sobre se esta opção será introduzida em algum momento?

Parece que a recomendação oficial é, de fato, migrar seu código de imagem para suportar a leitura desses tipos de variáveis ​​de um arquivo de texto secreto ± mantendo a capacidade de também ler essas variáveis ​​de ambiente para compatibilidade com versões anteriores sem pilha / enxame.

O exemplo usa um segredo por arquivo de texto, o que evita ter que analisar o arquivo .env antigo.

Parafraseado da documentação em 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

suspirar

Isso deveria ficar mais claro na documentação. Embora seja mencionado que .env não é suportado na seção Substituição de variável por @lengxuehx , não é mencionado que env_file é ignorado para implantações de pilha.

Posso confirmar que a solução proposta por @kinghuang funciona e não exclui a chave de implantação como alguém disse.

docker stack deploy -c <(docker-compose config) stack-name-here

Isso deveria ficar mais claro na documentação. Embora seja mencionado que .env não é suportado na seção Substituição de variável por @lengxuehx , não é mencionado que env_file é ignorado para implantações de pilha.

Posso confirmar que env_file é usado e está funcionando para o comando deploy stack, exatamente como o docker compose faz.

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

Para resumir, para pessoas como eu, que leram isso até agora:

  • docker stack deploy suporta "Substituição de Variável", mas você precisa definir as variáveis ​​de ambiente do arquivo .env de alguma forma. Várias opções foram explicadas acima. Uma das soluções mais legais é usar docker-compose config como pré-processador.
    Então você pode criar sua pilha com docker stack deploy -c <(docker-compose config) STACK_NAME .
  • Embora o Docker tenha introduzido os recursos de configurações e segredos , eles têm seus casos de uso, mas não farão a mesma coisa que "Substituição de variável".
  • O parâmetro env_file #$4$#$ no arquivo docker-compose.yml definirá as variáveis ​​de ambiente no contêiner criado e não no próprio arquivo docker-compose.yml (e, portanto, não pode ser usado como uma alternativa para " Substituição Variável").

Atualizar:

Fui corrigido por @thaJeztah.

O Docker não oferece suporte à substituição de variável usando a implantação da pilha do docker e nenhuma solução proposta funciona.

docker stack deploy suporta substituição de variáveis, mas não avalia o arquivo .env ; no exemplo abaixo, HELLO_VERSION é definido como linux e o serviço usará a tag hello-world:linux (em vez do padrão 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<strong i="14">@sha256</strong>:d073a5775c0b99d653c413161a8ed0e9685061afe697931d30eddf6afeef40f6

Dito isto, você ainda pode usar variáveis ​​de ambiente usando o parâmetro env_file em seu arquivo docker-compose.yml

O env_file serve a um propósito diferente (e é o equivalente a docker run --env-file ); a opção env_file especifica quais env-vars definir no contêiner que é criado, mas não é usado no próprio arquivo de composição (e não é usado para substituir variáveis ​​no arquivo de composição antes de implantar a pilha).

Eu tive o mesmo problema junto com outras pequenas diferenças entre docker-compose e docker stack.
Acabei criando https://github.com/egyel/dcsh script/tool ​​para lidar com esse problema com pipes.

image
Olá a todos, isso me ajudou a colocar env_file no meu docker-compose:

env_file: /path/to/env/file
não

env_file:
  - /path/to/env/file

Acabei de ver isso em outro post e só posso especular por que funciona (o mesmo que sua especulação), mas precisamos de confirmação de por que isso está funcionando como o docker mencionado explicitamente no docu que env_file não funciona.

Meu entendimento é que os arquivos env não podem ser usados ​​para preencher espaços reservados em
o arquivo docker-stack.yml, mas eles ainda podem ser fornecidos aos contêineres.
Observe que o que você está fazendo não permite definir o nome da imagem de
o arquivo env, por exemplo.

No domingo, 17 de maio de 2020, 06:08 raphyphy [email protected] escreveu:

[imagem: imagem]
https://user-images.githubusercontent.com/30310576/82135555-a1e4be00-9836-11ea-9df4-a1b82e014b0e.png
Olá a todos, isso me ajudou a colocar env_file no meu docker-compose:

env_file: /caminho/para/env/arquivo
não

env_file:

  • /caminho/para/env/arquivo

Acabei de ver isso em outro post e só posso especular por que funciona
(o mesmo que sua especulação), mas precisamos de confirmação de por que isso é
trabalhando como docker explicitamente mencionado no docu que env_file não
trabalhos.


Você está recebendo isso porque comentou.
Responda a este e-mail diretamente, visualize-o no GitHub
https://github.com/moby/moby/issues/29133#issuecomment-629740002 ou
Cancelar subscrição
https://github.com/notifications/unsubscribe-auth/ABHLQMCARDQGJQIBWCQKAYLRR5PMHANCNFSM4CYRHCTA
.

A solução docker-compose mencionada acima:

docker stack deploy -c <(docker-compose config) stack-name-here

tem a desvantagem (para mim) que coisas como arquivos .env e, especialmente, arquivos docker-compose.override.yml são normalmente mais parte do meu ambiente de desenvolvimento . Eu realmente não quero que eles sejam trazidos ao implantar na produção.

Acabei tendo um docker-compose-production.yml separado no qual eu controlava as coisas cuidadosamente, mesmo que isso envolvesse alguma duplicação.

Eu não acho que a CLI vai adicionar suporte .env . O comando docker stack deploy foi originalmente criado com os arquivos Distributed Application Bundle em mente (daí a opção --bundle-file ). Os arquivos DAB foram gerados pelo Docker Compose com o comando docker-compose bundle . .env e outros recursos do Compose seriam tratados por docker-compose , antes de serem passados ​​para docker stack deploy . O suporte direto para arquivos Compose em docker stack deploy sempre foi mais um compromisso.

A promessa original de arquivos DAB agora vive no Docker App, que também não processa .env .

Meus desenvolvedores usam docker-compose config para pré-processar projetos do Docker Compose antes de passá-los para docker stack deploy . Você pode fazer isso em uma linha com:

docker stack deploy -c <(docker-compose config) stack-name-here

Dessa forma, todos os recursos do Docker Compose, incluindo o processamento .env , são totalmente aplicados.

Isso funciona como um encanto, tenha em mente que se o seu arquivo de composição não tiver o nome "docker-compose.yml", seu comando deve incluir o nome real do arquivo de composição.

docker stack deploy -c <(docker-compose -f CUSTOM-COMPOSE-FILENAME.yml config) CUSTOM-STACK

CUIDADO com o HACK <(docker-compose -f CUSTOM-COMPOSE-FILENAME.yml config !!! A saída de docker-compose config e docker-compose -f myfile.yml config NÃO é necessariamente a mesma! O último às vezes envolve variáveis ​​env em aspas extras, então a saída estará errada!

Exemplo:

environment:
  SERVER_URL: '"xxx"'

em vez de

environment:
  SERVER_URL: xxx

Esse problema já está rastreado em algum lugar?

Esta página foi útil?
0 / 5 - 0 avaliações