Compose: Interpolar variáveis ​​de ambiente em docker-compose.yml

Criado em 30 abr. 2015  ·  109Comentários  ·  Fonte: docker/compose

(Estou criando um novo problema para isso, pois o antigo acumulou muita bagagem.)

Deve ser possível passar variáveis ​​de ambiente para o valor de qualquer * entrada de configuração em docker-compose.yml . Muitas pessoas querem fazer isso, é bom para a portabilidade e estou satisfeito que não vai causar o caos.

Eu tenho algumas estimativas.

Variáveis ​​necessárias e padrões opcionais

É útil poder especificar que uma variável que _deve_ estar presente no ambiente, ou seja, que o Compose se recusará a ser executado se não estiver. No entanto, isso será uma dor quando você tiver muitos deles, então deve ser algo que você habilite explicitamente ou deve ser possível especificar um valor padrão.

A implementação do MVP não precisa ter nenhum dos recursos, mas deve haver um caminho claro para a implementação de ambos de maneira compatível com versões anteriores.

Sintaxe

Há um forte caso para implementar um padrão estabelecido, desde que não seja pesado - nossos requisitos de funcionalidade são mínimos.

  • A expansão do parâmetro POSIX está OK. Tem muitos recursos, mas podemos implementar um subconjunto deles:

    • ${VARIABLE} - gera uma string vazia se VARIABLE não estiver definido

    • ${VARIABLE-default} - gera default se VARIABLE não estiver definido

    • ${VARIABLE?} - erros se VARIABLE não estiver definido

https://github.com/docker/compose/pull/845 implementou uma sintaxe ${VARIABLE:default} estilo Bash, que é semelhante à expansão do parâmetro POSIX, mas um pouco diferente.

Implementação

A função os.path.expandvars do Python implementa o caso mais básico de expansão do parâmetro POSIX:

>>> from os.path import expandvars
>>> expandvars('${HOME}')
'/Users/aanand'

No entanto, tem pelo menos 2 problemas:

  1. Uma variável não definida não se expande para uma string vazia - em vez disso, não resulta em expansão:

`` `

expandvars ('$ {UNSET}')
'$ {UNSET}'
`` `

  1. A sintaxe malformada não apresenta erros - em vez disso, também resulta em nenhuma expansão:

`` `

expandvars ('$ {HOME')
'$ {HOME'
`` `

Até agora, https://github.com/docker/compose/pull/845 é o mais próximo que temos, mas estou fundamentalmente desconfiado de uma implementação que depende de expressões regulares. A modelagem não é uma tarefa trivial, e as pessoas vão colocar todos os tipos de coisas quebradas, então precisamos de algo que seja robusto, rígido e com mensagens úteis. Dois requisitos importantes:

  • Se alguém inserir algo malformado, o Compose não será executado.
  • É possível escapar qualquer um dos caracteres especiais usados ​​na sintaxe do modelo.

Pode muito bem haver boas implementações de Python de interpolação de variável semelhante ao Bash por aí - se não, criar algo autônomo seria muito preferível a aumentar a base de código do Compose.

* Na verdade, há alguma chave de configuração para a qual _não devemos_ permitir a interpolação?

kinenhancement kinfeature

Comentários muito úteis

Meu caso de uso é permitir $PWD em volumes , para que cada desenvolvedor da equipe possa clonar um repositório para qualquer lugar e os caminhos ainda sejam montados corretamente.

elasticsearch:
  image: zinvoice/elasticsearch
  volumes:
    - $PWD:/app

Todos 109 comentários

Até onde você deseja ir com esses padrões UNIX estabelecidos? (FWIW, não é um padrão de fato, é um padrão real.)

Como alguém que ocasionalmente tenta acidentalmente usar expansões de parâmetro POSIX em Dockerfiles, se elas fossem suportadas em docker-compose.yml isso me faria um campista feliz.

@kojiromike Hmm, então a expansão do parâmetro POSIX é realmente o que eu estava

Edit: Eu atualizei meus pensamentos sobre a sintaxe na descrição.

Tenho seguido o tópico antigo e queríamos ter esse recurso com urgência. Finalmente a dor foi muito grande e criamos um script bahs pré-processador yaml para substituir variáveis ​​no estilo POSIX. funcionou bem, mas eventualmente paramos de usá-lo porque tinha um problema. Você deve executar o pré-processador primeiro e definir todos os parâmetros antes de obter a solução final. Agora estamos usando o recurso docker yaml extends. Porque nos permite verificar a configuração real e apenas executá-la no destino. Sabemos melhor o que vai acontecer.

Embora eu fosse um defensor da passagem de variáveis ​​docker-compose, agora não tenho tanta certeza.

Como uma solução ideal, eu preferiria ver o docker extends bem feito. Em certo sentido, essa seria uma solução adequada para ambos. Então, o que está quebrado no docker estende? É basicamente o fato de que você deve gravar todas as entradas no arquivo herdado. Não é uma fusão em que você insere apenas o que deseja substituir.

Veja nosso exemplo real e como ele é detalhado. Existem apenas duas linhas que importam.

#Common 
elasticsearch:
  image: zinvoice/elasticsearch
  hostname: elasticsearch
  restart: always
  dns: 172.17.42.1
  ports:
    - "9200:9200"
  volumes:
    - /etc/localtime:/etc/localtime:ro
    - /etc/timezone:/etc/timezone:ro
    - /data/elasticsearch:/opt/elasticsearch/data/elasticsearch

logstash:
  image: zinvoice/logstash
  hostname: logstash
  dns: 172.17.42.1
  restart: always
  ports:
    - "5000:5000"
  volumes:
    - /etc/localtime:/etc/localtime:ro
    - /etc/timezone:/etc/timezone:ro

kibana:
  image: zinvoice/kibana
  hostname: kibana
  dns: 172.17.42.1
  restart: always
  ports:
    - "5601:5601"
  volumes:
    - /etc/localtime:/etc/localtime:ro
    - /etc/timezone:/etc/timezone:ro

logspout:
  image: zinvoice/logspout
  hostname: logspout
  command: logstash://logstash.docker:5000
  restart: always
  dns: 172.17.42.1
  ports:
    - "8003:8000"
  volumes:
    - /var/run/docker.sock:/tmp/docker.sock

doorman:
  image: zinvoice/doorman
  hostname: doorman
  restart:  always
  dns: 172.17.42.1
  ports:
    - "8085:8085"
# inherited
elasticsearch:
  extends:
    file: ../common.yml
    service: elasticsearch

logstash:
  extends:
    file: ../common.yml
    service: logstash

kibana:
  extends:
    file: ../common.yml
    service: kibana

logspout:
  extends:
    file: ../common.yml
    service: logspout

doorman:
  environment:
    - DOORMAN_GITHUB_APPID=xxxxxxxx
    - DOORMAN_GITHUB_APPSECRET=xxxxxx
  links:
    - nginxtrusted
  extends:
    file: ../common.yml
    service: doorman

Portanto, meu docker de correção de recomendação estende e torna menos prolixo. Você nem mesmo precisa escrever tantos códigos, já que YAML fornece todas as funcionalidades de que você precisa. Se você seguir o YAML padrão, o arquivo poderá ser analisado ou criado por outras ferramentas e IUs.

Dê uma olhada em "âncoras de nó" YAML e "mesclagem de arquivos" YAML. Pode ser a solução perfeita.

Para sua informação: esta discussão continua agora no # 1380

@ Vad1mo Concordo que extends fica aquém no seu caso. Há muitas coisas que podemos fazer para melhorar essa experiência - você poderia abrir uma edição separada para isso, para que não sejamos desviados aqui?

Claro! Queria apenas destacar que esta pode ser uma alternativa fácil e elegante.
Se compose extends leva você a meio caminho de passagem de variável, então um compose-extends aprimorado tornará a passagem de variável obsoleta. Ter menos conceitos para entender torna mais fácil para o usuário.

Meu caso de uso é permitir $PWD em volumes , para que cada desenvolvedor da equipe possa clonar um repositório para qualquer lugar e os caminhos ainda sejam montados corretamente.

elasticsearch:
  image: zinvoice/elasticsearch
  volumes:
    - $PWD:/app

@mattes , acredito que já seja suportado, acho que .:/app é suportado

@aanand Como um PoC, fiz um hackup sujo do POSIX PE em Python . Para os sábados.

@kojiromike Parece ótimo. Deixe-me saber se você pretende continuar com isso.

@aanand eu pretendo, mas definitivamente tem alguns bugs (e eu acho que pode ter sido uma má ideia usar shlex ). Relatórios de bugs e PRs são bem-vindos, é claro.

@dnephin que tal $HOME / ~ ?

@nafg Ambos são suportados para o caminho do host de um volume

@dnephin interessante, b / c de alguma forma acabei com um diretório chamado '$ HOME' ...

@aanand Como a proposta "$ { VARIABLE: default }", com global_extends (ou "import") isso se tornaria bastante poderoso.

P: Isso permitiria especificar o número da porta que é exposta ao host? como - "$ {WEB_ PORT: 80 }: 80"?
O caso de uso é ser capaz de ativar facilmente várias instâncias de um aplicativo na mesma máquina / cluster, geralmente escutando portas diferentes ou atribuídas a diferentes nomes de domínio locais.

Sim, você seria capaz de fazer isso.

Eu gostaria de usar vars em volumes junto com docker-compose scale my_app=3 . Eu tenho este docker-compose.yml

server:
  image: alexanderilyin/docker-teamcity-server
  ports:
   - "8111:8111"
  volumes:
    - .TeamCity:/root/.BuildServer
  links:
   - mysql
mysql:
  image: alexanderilyin/docker-mysql
  volumes:
    - .MySQL:/var/lib/mysql
  environment:
    MYSQL_DATABASE: teamcity
    MYSQL_USER: teamcity
    MYSQL_PASSWORD: teamcity
    MYSQL_ALLOW_EMPTY_PASSWORD: yes
agent:
  image: alexanderilyin/docker-teamcity-agent
  links:
   - server

E eu quero poder usar scale para agentes e usar volumes dinâmicos para eles manterem os dados entre os lançamentos, por exemplo:

agent:
  image: alexanderilyin/docker-teamcity-agent
  volumes:
    - .agent_{$AGENT_INSTANCE_ID}:/opt/buildAgent
  links:
   - server

Espero que seja possível interpolar variáveis ​​como parte do nome da imagem também
Estamos usando https://github.com/openshift/source-to-image para construir um contêiner local em CI para cada branch e, em seguida, executar testes nele usando docker-compose.
A execução de testes com imagem dinâmica é bastante complicada com docker-compose e requer a renderização manual do modelo ..: -1:

Mas você pode definir COMPOSE_PROJECT_NAME para controlar o prefixo por execução para poder fazer isso certo? Em caso afirmativo, não há necessidade de lógica complexa e arquivos yml ilegíveis em torno dos nomes.

@andrerom não segue. De acordo com a documentação que controla o seguinte Sets the project name, which is prepended to the name of every container started by Compose enquanto tentamos definir uma propriedade de imagem:

web:
  image: <I_AM_DYNAMIC>

ah, erro meu.

Pensei que você quisesse dizer

<I_AM_DYNAMIC>:
  image: nginx

A referência dinâmica de imagem (e construção) realmente faria muito sentido. Por exemplo, alternar entre contêineres base de depuração e não depuração para sua linguagem de programação, por exemplo, seria um bom caso de uso para isso.

Caso de uso adicional _ (que pode ser o que @ Maxim-Filimonov tem em mente) _: Ser capaz de sobrescrever qual tag usar de uma imagem, então você pode usar: mais recente por padrão, mas mudar para testar facilmente outra coisa sem alterar yml arquivo _ (necessário para casos de uso de CI basicamente) _.

@andrerom esse é exatamente nosso caso de uso: +1:

Isso também funcionará para coisas como ??

web:
  environment:
    - FOO=${whoami}

@ k0377 Eu não acho que eles vão, porque isso é realmente algo que é tratado pelo shell, mas você pode adicionar o resultado em uma variável de ambiente e usar isso.

Neste caso particular, a variável de ambiente $USER provavelmente fornecerá o mesmo.

@aanand Por que não usar qualquer um dos mecanismos de modelo existentes que já estão presentes? Jinja2 está lá e funciona bem.

Como mencionado antes - implementar nosso próprio template não é uma tarefa trivial (e regexps não são tão legais), então devemos usar um já existente, que provou ser sólido.

Como alternativa, podemos usar ancors e referências YAML https://gist.github.com/bowsersenior/979804

Mas então estamos limitados no uso de variáveis ​​(injete o nome da variável no meio do conteúdo).

1 para Jinja2: certamente se encaixaria no molde e a ansible o usa para
exatamente esse caso de uso (modelagem em arquivos yml)

Na terça-feira, 26 de maio de 2015 às 13h25, tonnzor [email protected] escreveu:

@aanand https://github.com/aanand Por que não usar qualquer um dos modelos existentes
motores que já estão presentes? Jinja2 está lá e funciona bem.

Como mencionado antes - implementar nossos próprios modelos não é uma tarefa trivial
(e regexps não são tão legais), então devemos usar um já existente,
que provou ser sólido.

-
Responda a este e-mail diretamente ou visualize-o no GitHub
https://github.com/docker/compose/issues/1377#issuecomment -105493447.

Jinja2 faz _muito_ mais do que precisamos:

  • condicionais
  • looping
  • extensão / herança
  • comentários
  • filtros

Não estamos adicionando nada disso ao Compose. Se Jinja2 puder ser configurado para apenas interpolar variáveis, então ele pode ser um candidato.

Na verdade, fazer um loop pode ser interessante.

Suponha que você tenha uma lista de clientes para os quais deseja iniciar contêineres
onde você coloca algumas variáveis ​​específicas do cliente no ambiente.

Extensão / Herança pode ser interessante para melhorar o atual
mecanismo de extensão rudimentar.

Filtros podem ser ótimos para fazer algo com variáveis ​​existentes.

Na terça-feira, 26 de maio de 2015 às 13h56, Aanand Prasad [email protected]
escrevi:

Jinja2 faz _muito_ mais do que precisamos:

  • condicionais
  • looping
  • extensão / herança
  • comentários
  • filtros

Não estamos adicionando nada disso ao Compose. Se Jinja2 pode ser configurado
para apenas interpolar variáveis, então pode ser um candidato.

-
Responda a este e-mail diretamente ou visualize-o no GitHub
https://github.com/docker/compose/issues/1377#issuecomment -105498909.

Eles _podem_ ser recursos interessantes, mas vêm com muito mais complexidade do que me sinto confortável em apresentar o Compose e o formato de arquivo, e estaríamos vinculando ambos a uma linguagem de modelo específica com (até onde eu sei) uma única implementação e nenhuma especificação. Simplesmente não é viável.

@aanand Algumas notas aqui:

  1. Jinja2 é sólido e leva minutos para fazer o pré-processamento de YAML com ele:

from jinja2 import Template
template = Template ('Olá {{name}}!')
template.render (name = "Aanand")
Hello Aanand!

Se você quiser mais segurança, pode usar o sandbox imutável:

from jinja2.sandbox import ImmutableSandboxedEnvironment
env = ImmutableSandboxedEnvironment ()
template = env.from_string ('Olá {{nome}}!')
template.render (name = "Aanand")
Hello Aanand!

No nosso caso seria:

importar os
from jinja2.sandbox import ImmutableSandboxedEnvironment
env = ImmutableSandboxedEnvironment ()
template = env.from_string ('Olá {{nome}}!')
template.render (** os.environ)

  1. Não queremos filtros? Com o filtro, você pode definir o valor padrão facilmente ({{value | default ("default")}})
  2. Precisamos realmente nos preocupar com os usuários que usam recursos estendidos do Jinja para danificar o arquivo YAML? Da mesma maneira, o usuário pode produzir um arquivo YAML inválido manualmente. Acho que devemos mantê-lo simples - tente processar determinado modelo Jinja e retornar o erro se houver um erro ou se o YAML produzido for inválido (o mesmo que você faz agora).
  3. Se você não vê Jinja2 como solução - seria ótimo, pelo menos, usar {{variable}} como sintaxe.
  4. Django usa regexp para analisar e gerar template. É de qualidade de produção por um longo tempo e vive bem com ele.

importar os
importar re
template = "Olá {{name}}!"
re.sub ("{{\ s _ ([a-zA-Z0-9 _] +?) \ s_}}", lambda m: os.environ.get (m.group (1), ''), modelo)

Em qualquer caso - precisamos ter esse recurso funcionando, seja qual for a solução que escolhermos.

Estou com +1 sobre como usar uma solução de modelo genérico se os modelos forem considerados. Por exemplo, http://mustache.github.io , que está disponível em vários idiomas. Este é apenas um exemplo, outros motores de modelos podem ser considerados igualmente

@aanand eu entendo totalmente seu ponto. Eu também gosto da simplicidade e
sucinto do dsl composto.

Talvez isso deva ser feito como um projeto externo, digamos, meta-compositor. isto
pega um compose.tpl.yml e um variables.yml, cria um docker-compose.yml
e lá vamos nós.
Como @tonnzor mostrou, isso poderia ser feito com um pequeno pedaço de código python.

Isso proporcionaria modelos poderosos para aqueles que precisam sem
introduzindo complexidade para tarefas simples.

Na terça-feira, 26 de maio de 2015 às 16:52, Sebastiaan van Stijn <
notificaçõ[email protected]> escreveu:

Estou com +1 em usar uma solução de modelo _generic_ se os modelos
considerado. Por exemplo, http://mustache.github.io , que está disponível em muitos
línguas. Este é apenas um exemplo, outros motores de modelos podem ser
considerado igualmente

-
Responda a este e-mail diretamente ou visualize-o no GitHub
https://github.com/docker/compose/issues/1377#issuecomment -105551631.

Hmm ... Então é a proposta agora de usar uma linguagem de modelos dentro de compose.yml (que é uma linguagem descritiva para compor containers Docker), para coisas como command e entrypoint , que já aceitam ambos exec e sh -c valores de estilo? Isso pode ser confuso, já que após a renderização do modelo, o comando shell resultante ainda seria interpretado, portanto, se uma variável se expandisse para * ela seria posteriormente expandida. Escapar sequências em um idioma ou outro torna-se complicado quando você tem tantas camadas de interpretação incompleta.

@kojiromike Não tenho certeza se um motor de template é desejado, mas se for para ser usado! melhor usar algo bem conhecido. A questão básica é; deve docker-compose escrever a substituição do zero ou usar algo existente.

Em Ter, 26 de maio de 2015, 11:02 Christoph Witzany [email protected]
escrevi:

@aanand eu entendo totalmente seu ponto. Eu também gosto da simplicidade e
sucinto do dsl composto.

Talvez isso deva ser feito como um projeto externo, digamos, meta-compositor. isto
pega um compose.tpl.yml e um variables.yml, cria um docker-compose.yml
e lá vamos nós.

Você pode fazer isso hoje, sem nenhum novo projeto. Tenho certeza que jinja pode ser
invocado da linha de comando de alguma forma. Pessoalmente, eu só uso o envsubst
comando.

O que seria realmente útil é se o compose pudesse ler o arquivo de stdin.
Isso eliminaria a necessidade de um arquivo intermediário.

Como @tonnzor mostrou, isso poderia ser feito com um pequeno pedaço de código python.

Isso proporcionaria modelos poderosos para aqueles que precisam sem
introduzindo complexidade para tarefas simples.

Na terça-feira, 26 de maio de 2015 às 16:52, Sebastiaan van Stijn <
notificaçõ[email protected]> escreveu:

Estou com +1 em usar uma solução de modelo _generic_ se os modelos
considerado. Por exemplo, http://mustache.github.io , que está disponível em muitos
línguas. Este é apenas um exemplo, outros motores de modelos podem ser
considerado igualmente

Responda a este e-mail diretamente ou visualize-o no GitHub
https://github.com/docker/compose/issues/1377#issuecomment -105551631.

Responda a este e-mail diretamente ou visualize-o no GitHub
https://github.com/docker/compose/issues/1377#issuecomment -105554730. src = "
https://ci6.googleusercontent.com/proxy/iSBXyl7D8PwFM4p1mGPHCR7bQctunieGbhyGkvo0QIMIjmAYE3I0Mt96yl1fGrqcuOzxV4APP8ZRIw-5_qd6nzps9Mpr6jTAydCC4xs8JDgqm93aIbWvN1eMlxykrz7iwYooyAQdqL4RFJokeEbnBkZm5mhgKg=s0-d-e1-ft#https://github.com/notifications/beacon/AAGAUO8xqz29B2SUoG7QFPUy848_JJW9ks5oNIJlgaJpZM4EMysO.gif
">

1 para ler o arquivo de stdin. Não tenho nenhum problema em usar uma solução de modelo externo, mas não ter arquivos intermediários por perto seria bom.

Isso parece um ótimo primeiro passo e uma característica comum de muitas ferramentas CLI. Vamos fazer isso

: +1:

Então por exemplo

envsubst compose.tmpl.yml | docker-compose -f - up -d

wfm. : +1:

Acabei de notar que docker / distribution lida com valores de substituição no arquivo yml por meio de variáveis ​​de ambiente, mas usando uma abordagem diferente https://github.com/docker/distribution/blob/master/docs/configuration.md#override -configuration-options

^^ @aanand

@thaJeztah isso funcionaria para nós também. Podemos usar variáveis ​​de ambiente para substituir comandos, então

DOCKER_COMPOSE_IMAGE_NAME='my_image:is_dynamic'

Abordagem interessante, mas não sou um fã - nomes de variáveis ​​de ambiente detalhados, muita duplicação se você quiser usar um valor em vários lugares, tudo está implícito, sem interpolação dentro de strings.

@aanand também não

Acabei de tropeçar em https://github.com/kelseyhightower/confd que pode ser do seu interesse. Ele usa http://golang.org/pkg/text/template/#pkg -overview

@olalonde infelizmente, docker-compose é escrito em Python, então Go-templates não funcionam.

@aanand eu sou +20 em sua proposta original, com o ajuste que mesmo imagens e especialmente tags devem ser possíveis de injetar. Simplesmente vá em frente, economizaria muitos invólucros e manipulação desnecessária de configurações;)

Eu escrevi um pequeno pacote python que me ajuda com isso. O plano é fazer um túnel de todos os comandos para o docker compose para que você possa usá-lo de forma equivalente.
Confira em https://github.com/webcrofting/meta-compose/

meta-composição parece muito bom. Deve ser integrado ao docker-compose!

Grande +1 aqui - não estou entusiasmado com o pré-processamento de modelos, mas puxar variáveis ​​de ambiente de uma forma ou de outra seria ótimo. A expansão POSIX é provavelmente mais limpa do que Jinja2, mas de qualquer forma é bom.

Grande +1 daqui também. Meu caso de uso é mais para adicionar suporte de ID de publicidade dinâmica para contêiner kafka, que é vital para produtores de dados (que podem ser outros contêineres).

Também estou animado com esse recurso.

A expansão POSIX é provavelmente mais limpa do que Jinja2, mas de qualquer forma é bom.

Acho que outro argumento a favor da expansão POSIX é que ela não tem lógica. O Jinja2 suporta algum grau de lógica condicional / de loop (como a maioria dos motores de modelos fazem, mesmo aqueles que afirmam ser "sem lógica"). Misturar lógica de modelos e YAML é muito estranho na minha experiência. Alguém pode pensar em um caso de uso para tal lógica? Caso contrário, pode ser melhor evitar especificamente o suporte por enquanto.

Seria bom ter uma resposta clara dos desenvolvedores sobre esse recurso. Lendo várias questões e RP, não fica claro se você realmente deseja implementá-lo ou não.

Se sim, com que tipo de mecanismo? Caso contrário, as pessoas podem começar a construir algumas ferramentas de terceiros para gerenciar o recurso.

Obrigado !

Ok, acabei de ver https://github.com/docker/compose/pull/76. Acho que a resposta está aí ...

Percorreu alguns ciclos sobre as questões / RPs vinculadas.

AFAIK, a comunidade nginx se recusou a adotar qualquer mecanismo de modelo para arquivos de configuração, mesmo para uma substituição de variável simples. Por quê? Talvez eles ainda estejam escolhendo um mecanismo de template ideal: smile :

@hadim

Lendo várias questões e RP, não fica claro se você realmente deseja implementá-lo ou não.

Esse problema deveria fornecer a resposta definitiva para essa pergunta, então, sinto muito não ter sido claro: sim, queremos implementá-lo e com uma sintaxe no estilo POSIX.

obrigado @aanand !

Obrigado, @aanand.

1 para mim. Preciso passar --dns = (endereço da ponte docker0) e preciso que funcione se isso mudar em versões futuras do docker, portanto, uma variável de ambiente e / ou shell é perfeita. meta-compose não funciona para mim, pois deve suportar DOCKER_HOST remoto e, por exemplo, via docker-swarm, não apenas localmente.

: +1: Isso seria muito bom. Atualmente, ou acabo gerando o arquivo .yml por meio de outro script ou simplesmente não estou usando docker-compose completamente e - vinculando dockers manualmente.

:afirmativo:

Acho que a interpolação básica de variáveis ​​de ambiente seria muito útil para coisas simples.

Alguns casos de uso simples:

  • Ser capaz de especificar dinamicamente a tag de uma imagem para puxar de um repositório remoto.
  • Ser capaz de definir o mapeamento da porta para um contêiner.

Ferramentas como o Ansible já fazem modelos muito bem, então não tenho certeza se um mecanismo de modelo completo é necessário. Mas não poder ter nenhum conteúdo dinâmico no arquivo comose.yml é muito limitante.

Com relação ao PR # 1488 mesclado, estou particularmente interessado em enviar um arquivo de configuração para docker-compose . Não consigo entender por que docker-compose não pode pegar de um processo de nó.

var spawn = require('child_process').spawn;

var compose = spawn('docker-compose', ['--file' + '-' + 'up']);

compose.stdin.setEncoding = 'utf-8';

compose.stdout.on('data', function (data) {
    console.log('"docker-compose --file - up" stdout: "%s".', data);
});

compose.stderr.on('data', function (data) {
    console.log('"docker-compose --file - up" returned an error: "%s".', data);
});

compose.on('close', function (code) {
    if (code !== 0) {
        console.log('"docker-compose --file - up" existed with an erroneous code: "%s".', code);
    } else {
        console.log('"docker-compose --file - up" existed with code: "%s". SUCCESS!', code);
    }
});

compose.stdin.write("redis: {\"image\": \"redis\"}\n");
compose.stdin.end();

Algum exemplo de como canalizar dados do Node.js?

Outra coisa que descobri é que docker-compose 1.4.0-RC1 está enviando algumas mensagens aparentemente normais como Starting... ou Attaching... para stderr vez de stdout .

@kadishmal Você poderia abrir edições separadas para eles, por favor?

Outra sugestão de sintaxe / implementação: o modelo de string do Python, conforme especificado no PEP 0292 e implementado no string.Template .

É muito semelhante à expansão do parâmetro POSIX:

  • $foo expande para o valor de foo
  • ${foo} expande para o valor de foo
  • $ , ${ , $} , ${} , ${foo , $ {foo} , ${ foo} , ${foo } são erros

Desvantagens:

  • Sem valor padrão ou sintaxe de "valor obrigatório". Ainda assim, poderíamos decidir mais tarde se os queremos o suficiente para merecer escrever nosso próprio código de modelagem.
  • As mensagens de erro não expõem nenhuma informação legível por máquina sobre onde está o erro de sintaxe (isto é, sem realizar a correspondência de regex na string de erro).
  • A sintaxe de escape difere de POSIX: $$ vez de \$ .

Isso pode realmente ser uma bênção disfarçada: YAML não gosta de \$ e requer que você escape duas vezes. Eu não acho que dizer às pessoas para digitar \\$ apenas para obter um cifrão vai funcionar.

Eu detectei uma implementação em # 1765.

+1

Não tenho certeza se este é o lugar certo para isso, ou se devo fazer uma nova edição.

Acho que a precedência de env deve ser o contrário, ou seja, uma variável do shell que invoca docker-compose deve substituir qualquer variável dentro de docker-compose.yml, que por sua vez deve substituir qualquer variável definida pelo contêiner.

Aqui está o que acontece atualmente quando eu tento:

docker-compose.yml:

test:
    image: ubuntu
    environment:
        - FOO="from compose"

e então execute-o com o comando env :

docker-compose run test env | grep FOO

FOO="from compose" , como esperado. Mas então:

FOO="from shell" docker-compose run test env | grep FOO

também dá FOO="from compose" , mas aqui eu esperava FOO="from shell" .

Algumas pessoas ainda podem precisar de interpolação de variável para outros casos de uso, mas alterá-la satisfaria o caso "padrão" - efetivamente a environment: definição / valor em docker-compose.yml é o padrão e pode ser substituído em tempo de execução, se necessário, sem a necessidade de qualquer sintaxe YAML extra.

@fazy você não levou em conta que o comando env foi executado no contêiner test isolado no qual o FOO é from compose (apenas como deveria ser e como foi configurado em um arquivo docker-compose ). Mas fora desse contêiner se docker-compose processo tivesse algum tipo de função de impressão para a variável de ambiente que você configurou antes do comando, ele teria impresso 'do shell' porque é o valor para o host (bem como para o processo docker-compose ) em que você está executando. Talvez você estivesse esperando que o FOO fosse from shell neste caso, mas pessoalmente eu ficaria muito surpreso se fosse. (Espero que, apesar do meu inglês, você compreenda meu ponto).

@smileart obrigado, acho que entendo o que você está dizendo.

No entanto, o contêiner test não está completamente isolado, ele obtém seu ambiente de docker-compose (ou pelo menos, docker-compose é capaz de definir variáveis ​​de ambiente no contêiner iniciado) e docker-compose em si pode ver a variável de ambiente "externa".

Você pode ver com este docker-compose.yml:

test:
    image: ubuntu
    environment:
        - FOO

Então o comando:

FOO="from shell" docker-compose run test env | grep FOO

realmente dá o resultado "do shell".

Portanto, minha pergunta é sobre precedência. Especificando apenas o nome da variável aqui, - FOO , posso injetar a variável de fora. Mas se eu especificar - FOO=something _and_ injetar uma variável de fora, qual deve ter precedência? IMHO a variável especificada na linha de comando deve ter precedência sobre o arquivo de configuração.

@fazy Oh, desculpe, eu não tentei FOO="from shell" docker-compose run test env | grep FOO sem especificar seu valor em docker-compose.yml e eu não sabia que isso nos dá o FOO do host. Então não seria apenas estranho para mim: smiley: Eu pensei que configurar uma variável de ambiente antes de docker-compose influenciaria em docker-compose e docker-compose SOMENTE sem jogá-la no recipiente. Agora eu vejo o que você quis dizer.

Acabei de descobrir a desvantagem de escapar de $ mencionado em https://github.com/docker/compose/issues/1377#issuecomment -124571722. Primeiro eu fiz apenas FOO=ba$e depois FOO='ba$e' (esquecendo que é considerado "puro"), depois FOO=ba\$e , depois FOO=ba\\$e , desisti e fui para os documentos, apenas para ficar surpreso ao descobrir que " $ é o caractere de escape para $ ". Para mim, isso não foi particularmente "menos surpresa".

Porém, não sei qual seria a boa solução.

@ ct-clearhaus Compose não é o único programa que usa $ para escapar $ . Você também encontrará isso em makefiles. Portanto, para algumas pessoas, esse idioma é bastante familiar.

Eu amo a implementação de substituição de variável existente. No entanto, eu realmente poderia usar a capacidade de definir um padrão, de acordo com a proposta original de

${ENV-default}

Meu uso específico é poder especificar a porta do host em que o serviço é executado:

PORT=8123 docker-compose up

Adicionando isso ao meu docker-compose.yml :

web:
  ports:
    - "${PORT-8000}:5000"

Este recurso ainda está planejado e em desenvolvimento?

Tentei resolver meu problema com extensões , mas ficou muito confuso. Não apenas tive que duplicar quase todas as minhas docker-compose.yml apenas para alterar uma configuração, também não há como _alterar_ uma configuração de porta exposta, você pode apenas add to a lista de portas expostas, que não é ideal para mim.

Por que docker-compose não falha quando as variáveis ​​de ambiente não estão definidas? Ele apenas registra um aviso e continua. Não seria apenas retornar e errar uma abordagem melhor ...
WARNING: The FOO variable is not set. Defaulting to a blank string.

1 para sintaxe POSIX para declarar valores padrão

Talvez esteja faltando algo óbvio, mas gostaria de poder usar variáveis ​​de ambiente de um env_file para definir o valor de uma variável de ambiente, por exemplo:

docker-compose.env:

DB_PASSWORD=test

docker-compose.yaml:

...
service:
    database:
        env_file:
            - ./docker-compose.env
        environment:
            - MYSQL_PASSWORD=${DB_PASSWORD}
    webserver:
        env_file:
            - ./docker-compose.env
        environment:
            - WORDPRESS_DB_PASSWORD=${DB_PASSWORD}

Isso poderia ser realizado de alguma outra maneira? Não quero ter um arquivo de modelo yaml que precise ser canalizado por meio de envsubst.

Por que não colocar esse valor diretamente em env_file do jeito que você quiser?

2636 suportará um arquivo env para valores padrão

Isso significaria ter uma variável que deve ter o mesmo valor em dois lugares, torna mais fácil se você só precisar alterar um. # 2636 parece promissor.

Precisamos desesperadamente de um mecanismo para suportar variáveis ​​padrão agora, pois as limitações existentes nos forçam a usar scripts de wrapper para ajudar docker-compose. Preciso de coisas como NODE_ENV=${NODE_ENV:-dev} para funcionar e, por conveniência, seria bom ter SOME_NUMBER=$((96*60)) para funcionar. Isso estava programado para uma versão futura?

+1 para valores padrão

+1 para valores padrão. isso está se tornando crítico para nós.

Concordo @ darkn3rd - preciso obter o ID do usuário e o ID do grupo de usuários para configurá-los no contêiner. A única maneira que encontrei é forçar minha equipe a exportar 2 vars ... ou usar um makefile que fiz para exportá-los.

Se eu pudesse fazer:

    user: $((id -u)):$((id -g))

isso vai resolver todos os meus problemas

@mgor Parece que você poderia simplesmente passar por envsubst ?

env $(cat docker-compose.env | xargs) envsubst < docker-compose.tmpl > docker-compose.yml

deve fazê-lo (sem poluir o ambiente persistente), eu acho.

@OJFord @mgor Sem intenção de roubar o thread, mas desenvolvi algumas ferramentas CLI para ter um fluxo de trabalho mais limpo; envset e slv .

envset development -- slv docker-compose.tpl > docker-compose.yml

envset carregará variáveis ​​de um arquivo env na sessão shell atual, slv substitui o modelo usando variáveis ​​ambientais.

Eu concordo com @OJFord mas não é disso que preciso ...
Deixe-me ser mais preciso: somos uma equipe de 40 desenvolvedores que usa uma pilha docker-compose diferente. Estamos usando git para obter o código.

Se eu pedir a eles para modificar docker-compose.yml que é entregue por nosso git, então tenho certeza que alguém enviará um arquivo docker-compose.yml modificado ... Confie em mim, esse será o caso.

Posso "gerar um arquivo base composer" que é ignorado por git e estendido por docker-compose.yml, mas para gerá-lo vou precisar dar a eles um Makefile ou um bashscript ... Chegará o dia em que " a mudança do arquivo docker "será necessária e a equipe não saberá que será necessário executar novamente a geração.

O mesmo para um arquivo "env", que é muito bom, mas não funciona com "build" e preciso pedir à minha equipe para gerar este arquivo.

Realmente, se docker-compose puder obter valores de bash (ou qualquer outra solução que retorne algo que uma var ENV) no arquivo yaml resolverá muitas necessidades.

Meu exemplo em meu comando anterior é perfeito: eu preciso obter a id do usuário e gid e esses valores não são definidos por ENV vars. Portanto, preciso pedir à minha equipe que escreva suas identidades em um arquivo .env ... Simples para mim e para você, não para todos.

Para ser mais preciso: preciso fornecer um arquivo docker-compose que não deve ser alterado pela equipe, porque está em um repositório git.

Este pull-request é um exemplo simples que funciona para mim. Talvez você possa me ajudar a fazer melhor.

Tentei com as diretivas de ambiente e de usuário do arquivo docker-compose.yml. Funciona bem por enquanto.

O valor padrão deve estar lá ... Muito útil ... Desenvolvedores e OPS estão usando os logs do docker ou syslog ... Então, eles geralmente precisam criar o LOG_FORMAT padrão mostrado abaixo ... Poderíamos apenas ter o valor padrão e só usá-lo ao mudar para o syslog ...

default:
  extends:
    file: base.yml
    service: base-${LOG_FORMAT:docker}
  labels:
    - "net.company.npmjs.datacenter=${DATA_CENTER}"
    - "net.company.npmjs.env=${ENV}"
    - "net.company.npmjs.hostname=${HOSTNAME}"
    - "net.company.npmjs.role=${NPMO_ROLE}"
    - "net.company.npmjs.log=${LOG_FORMAT}"

base-syslog:
  log_driver: syslog
  log_opt:
    tag: "{{.ImageName}}/{{.Name}}/{{.ID}}"

base-docker:
  log_driver: json-file
  log_opt:
    max-size: "128m"
    max-file: "4"

Quando isso estará disponível? Estou no Compose 1.7.0 e ainda não está lá :(

Por favor, forneça os valores padrão!

@marcellodesales : Talvez você possa tirar vantagem de usar um arquivo docker-compose.override.yml alguma forma. Verifique esse recurso.

Também +1 em env vars. É nosso maior problema com docker-compose hoje em dia.

Eu insistiria em meu PR # 3367 para poder obter certos valores do host. :)

@pataquets Acho que não quero criar outro arquivo de substituição ... nosso arquivo base.yml , como mostrado acima, mostra todas as coisas suportadas em termos de driver de logger, etc ... Eu só quero mudar e têm valores padrão. Eu acho que precisaríamos manter ainda mais arquivos yml. Mas vou manter isso em mente para o caso.

+1

+1

+1

+1

Qualquer aviso sobre o uso de variáveis ​​de ambiente em docker-compose?

+1

+1

FYI: Vars de ambiente para docker-compose funciona a partir de 1.7.0. Você também pode definir variáveis ​​padrão docker-compose em .env no mesmo diretório do arquivo raiz docker-compose.yml . Isso não deve ser confundido com os envfiles do docker, já que é uma coisa diferente.

Existe uma maneira de definir o nome do serviço como uma variável?

Em vez de escrever isso

services:
   site_db:
     image: mysql:5.7

Poderíamos escrever

services:
   ${CONTAINER_NAME}:
     image: mysql:5.7

Meu objetivo é manter o mesmo docker-compose.yml em vários sites e apenas alterar o arquivo .env . No momento, ainda preciso modificar o nome do contêiner porque estou executando vários aplicativos no mesmo host. E gostaria que cada serviço tivesse seu próprio nome para maior clareza.

@LouWii você pode usar

services:
    site_db:
      container_name: "${CONTAINER_NAME}"
      image: mysql:5.7

ou (formato de arquivo de composição 2.1 e superior)

services:
    site_db:
      container_name: "${CONTAINER_NAME:-defaultname}"
      image: mysql:5.7

Mas por que não definir o nome do projeto? O nome do projeto é _intendido_ para isso, uma vez que ele prefixa / coloca nomes de contêineres que são criados para evitar conflito com outros projetos no mesmo host. Consulte https://docs.docker.com/compose/reference/envvars/#/composeprojectname

@thaJeztah Obrigado! Ainda estou aprendendo como o Docker e a composição do docker funcionam. Definir o nome do projeto parece ser a melhor opção, faz todo o sentido no meu uso.

Existe alguma maneira de fazer o script dentro das chaves interpoladas? Por exemplo ${HOST_PORT + 1} .

Você pode canalizar o arquivo através do Jinja ou algo assim ...

Em Ter, 24 de janeiro de 2017, 5:36 AM Sam A. Horvath-Hunt [email protected]
escrevi:

Existe alguma maneira de fazer o script dentro das chaves interpoladas? Por exemplo $ {HOST_PORT

  • 1}

-
Você está recebendo isso porque foi mencionado.
Responda a este e-mail diretamente, visualize-o no GitHub
https://github.com/docker/compose/issues/1377#issuecomment-274767368 ,
ou silenciar o tópico
https://github.com/notifications/unsubscribe-auth/AAGAUN5ZrU39dnVVVASwIHr5mGqJFxh3ks5rVdRIgaJpZM4EMysO
.

Consigo escapar de $ ?

environment:
   PATH: "$PATH:/home/appuser/.bundler/bin"

Atualmente, isso resulta na variável PATH do host sendo interpolada e não no contêiner

é um arquivo docker-compose.yml encontrado apenas um?
como posso adicionar ou modificar?
desde já, obrigado

@logicminds embora eu não conseguisse encontrar documentado em lugar nenhum, encontrei $$ interpola para um $ com escape.

environment:
   PATH: "$$PATH:/home/appuser/.bundler/bin"

@elquimista tem uma solução que achei útil https://github.com/mhart/alpine-node/issues/48#issuecomment -430902787

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