Compose: Execute um comando após executar

Criado em 5 ago. 2015  ·  131Comentários  ·  Fonte: docker/compose

Oi,

Será muito útil ter algo como "onrun" no YAML para poder executar comandos após a execução. Semelhante a https://github.com/docker/docker/issues/8860

mongodb:
    image: mongo:3.0.2
    hostname: myhostname
    domainname: domain.lan
    volumes:
        - /data/mongodb:/data
    ports:
        - "27017:27017" 
    onrun:
        - mongodump --host db2dump.domain.lan --port 27017 --out /data/mongodb/dumps/latest
        - mongorestore -d database /data/mongodb/dumps/latest/database

Após o início do mongodb, ele irá despejar db2dump.domain.lan e restaurá-lo.

Quando eu parar e iniciar o contêiner, a parte onrun não será executada para preservar a idempotência.

EDITAR 15 de junho de 2020

5 anos depois, o Compose não quer "padronizar" as especificações,
verifique https://github.com/compose-spec/compose-spec/issues/84

Comentários muito úteis

Então, para gerenciar meu docker, você me sugere usar um Script ou um Makefile. Então, por que a composição foi criada
? Podemos gerenciar, dimensionar, etc. container com script || dockerfile?

Ok, eu pego este exemplo, é o que usei para implantar meu ambiente de teste de aplicativos no processo de CI.

rabbitmq:
    image: rabbitmq:3.5.1-management
    environment:
        RABBITMQ_NODENAME: rabbit
    hostname: rabbitmq
    domainname: domain.lan
    volumes:
        - /data/rabbitmq/db:/var/lib/rabbitmq
    ports:
        - "5672:5672" 
        - "15672:15672"
        - "25672:25672"
        - "4369:4369"

mongodb:
    image: mongo:3.0.2
    hostname: mongo
    domainname: domain.lan
    volumes:
        - /data/mongodb:/data
    ports:
        - "27017:27017" 

appmaster:
    image: appmaster
    hostname: master
    domainname: domain.lan
    environment:
        ...
    ports:
        - "80:80" 
        - "8080:8080"
    links:
        - mongodb
        - rabbitmq

celery:
    image: celery
    hostname: celery
    domainname: domain.lan
    environment:
        ...
    links:
        - rabbitmq

Depois que o contêiner é iniciado, devo provisionar o mongodb, gerenciar a fila e a conta no rabbitmq

O que estou fazendo hoje é um script com:

#!/bin/bash
PROJECT=appmaster
docker-compose -f appmaster.yml -p appmaster up -d
docker exec appmaster_rabbitmq_1 rabbitmqctl add_user user password
docker exec appmaster_rabbitmq_1 rabbitmqctl add_vhost rabbitmq.domain.lan
docker exec appmaster_rabbitmq_1 rabbitmqctl set_permissions -p rabbitmq.domain.lan password ".*" ".*" ".*"
docker exec appmaster_mongodb_1 mongodump --host mongo-prd.domain.lan --port 27017 --out /data/mongodb/dumps/latest
docker exec appmaster_mongodb_1 mongorestore -d database /data/mongodb/dumps/latest/database

Com a instrução onrun posso fazer diretamente docker-compose -f appmaster.yml -p appmaster up -d
e o arquivo yml se torna mais legível

rabbitmq:
    ...
    onrun:
        - rabbitmqctl add_user user password
        - rabbitmqctl add_vhost rabbitmq.domain.lan
        - rabbitmqctl set_permissions -p rabbitmq.domain.lan password ".*" ".*" ".*"

mongodb:
    ...
    onrun:
        - mongodump --host mongo-prd.domain.lan --port 27017 --out /data/mongodb/dumps/latest
        - mongorestore -d database /data/mongodb/dumps/latest/database

Todos 131 comentários

Acho que essas devem ser etapas no Dockerfile

FROM mongo:3.0.2
ADD data/mongodb/dumps/latest /data/mongodb/dumps/latest
RUN mongorestore -d database /data/mongodb/dumps/latest/database

Dessa forma, você também o armazena em cache ao reconstruir.

Obrigado @dnephin.
Claro que posso fazer um Dockerfile e usá-lo na construção em vez de imagens, ou posso usar o docker exec.
MongoDB é apenas um exemplo, você pode ter este exemplo com mysql e criação de conta ou com rabbitmq e criação de fila, etc.

onrun permitirá flexibilidade na orquestração da composição, a composição lerá a lista de execução e fará docker exec em cada item.

A questão é que colocar comandos em docker exec em docker-compose.yml é desnecessário quando você pode fazer isso no Dockerfile ou no script de inicialização do contêiner, ambos os quais também tornarão seu contêiner mais útil quando _not_ sendo executado com Compose.

Como alternativa, inicie seu aplicativo com um script de shell ou Makefile que execute os comandos docker e docker-compose apropriados.

Não vale a pena adicionar a funcionalidade ao Compose, a menos que agregue valor significativo em relação a qualquer um desses itens, e não acho que seria para os casos de uso que você citou.

Então, para gerenciar meu docker, você me sugere usar um Script ou um Makefile. Então, por que a composição foi criada
? Podemos gerenciar, dimensionar, etc. container com script || dockerfile?

Ok, eu pego este exemplo, é o que usei para implantar meu ambiente de teste de aplicativos no processo de CI.

rabbitmq:
    image: rabbitmq:3.5.1-management
    environment:
        RABBITMQ_NODENAME: rabbit
    hostname: rabbitmq
    domainname: domain.lan
    volumes:
        - /data/rabbitmq/db:/var/lib/rabbitmq
    ports:
        - "5672:5672" 
        - "15672:15672"
        - "25672:25672"
        - "4369:4369"

mongodb:
    image: mongo:3.0.2
    hostname: mongo
    domainname: domain.lan
    volumes:
        - /data/mongodb:/data
    ports:
        - "27017:27017" 

appmaster:
    image: appmaster
    hostname: master
    domainname: domain.lan
    environment:
        ...
    ports:
        - "80:80" 
        - "8080:8080"
    links:
        - mongodb
        - rabbitmq

celery:
    image: celery
    hostname: celery
    domainname: domain.lan
    environment:
        ...
    links:
        - rabbitmq

Depois que o contêiner é iniciado, devo provisionar o mongodb, gerenciar a fila e a conta no rabbitmq

O que estou fazendo hoje é um script com:

#!/bin/bash
PROJECT=appmaster
docker-compose -f appmaster.yml -p appmaster up -d
docker exec appmaster_rabbitmq_1 rabbitmqctl add_user user password
docker exec appmaster_rabbitmq_1 rabbitmqctl add_vhost rabbitmq.domain.lan
docker exec appmaster_rabbitmq_1 rabbitmqctl set_permissions -p rabbitmq.domain.lan password ".*" ".*" ".*"
docker exec appmaster_mongodb_1 mongodump --host mongo-prd.domain.lan --port 27017 --out /data/mongodb/dumps/latest
docker exec appmaster_mongodb_1 mongorestore -d database /data/mongodb/dumps/latest/database

Com a instrução onrun posso fazer diretamente docker-compose -f appmaster.yml -p appmaster up -d
e o arquivo yml se torna mais legível

rabbitmq:
    ...
    onrun:
        - rabbitmqctl add_user user password
        - rabbitmqctl add_vhost rabbitmq.domain.lan
        - rabbitmqctl set_permissions -p rabbitmq.domain.lan password ".*" ".*" ".*"

mongodb:
    ...
    onrun:
        - mongodump --host mongo-prd.domain.lan --port 27017 --out /data/mongodb/dumps/latest
        - mongorestore -d database /data/mongodb/dumps/latest/database

Isso seria bastante útil e resolveria um caso de uso.

: +1:

Isso tornará o uso de docker-compose mais viável para testes bloqueados como parte de um pipeline de CD

: +1:

Esta é uma duplicata de # 877, # 1341, # 468 (e alguns outros).

Acho que a maneira certa de dar suporte a isso é # 1510 e permitir que ferramentas externas executem operações quando você chegar ao evento desejado.

Fechando como uma duplicata

Isso seria muito útil. Eu não entendo o argumento de "oh, você poderia fazer isso com um script bash". Claro que poderíamos fazer isso com um script bash. Eu também poderia fazer tudo o que o Docker-compose faz com um script bash. Mas o ponto é que há um único arquivo YAML que controla seu ambiente de teste e pode ser ativado com um comando docker-compose up simples.

Não é responsabilidade do Compose fazer _tudo_ que poderia ser feito com um script shell ou Makefile - temos que traçar uma linha em algum lugar para encontrar um equilíbrio entre a utilidade e evitar o inchaço.

Além disso, uma propriedade importante do arquivo Compose é que ele é bastante portátil entre máquinas - até mesmo máquinas Mac, Linux e Windows. Se permitirmos que as pessoas coloquem comandos de shell arbitrários no arquivo Compose, eles ficarão muito menos portáveis.

@aanand Para ser justo, ser capaz de executar docker exec não implica automaticamente em incompatibilidade de x-plat.

Desculpas - eu interpretei mal este problema como sendo sobre a execução de comandos na máquina host. Ainda assim, meu primeiro ponto permanece.

Eu entendo seu ponto @aanand. Não me parece fora do escopo, uma vez que docker-compose faz muitas das mesmas coisas que o motor docker normal já faz, como command , expose , ports , build , etc. Adicionar a funcionalidade exec adicionaria mais poder a docker-compose para torná-lo um verdadeiro balcão único para configuração ambientes de desenvolvimento.

@aanand o principal problema para muitos desenvolvedores e pipelines de CI é ter dados muito próximos do env de produção. Como um despejo de um banco de dados. Eu criei este tíquete há 1 ano e nada se move no docker compose.

Então, você sugere um Makefile ou um Bashcript apenas para executar algum exec https://github.com/docker/compose/issues/1809#issuecomment -128073224

O que eu originalmente sugiro é onrun (ou oncreate) que mantém a idempotência. Apenas corra na primeira partida. Se o contêiner for interrompido ou pausado, o novo início não será executado durante a execução (ou na criação)

Finalmente, no meu repositório git terei um arquivo de composição, um dockerfile e um makefile com gerenciamento de idempotência (pode makefile criar um arquivo de estado). Gênio!

Há uma grande diferença entre command , expose , etc. e exec . O primeiro grupo são opções de contêiner, exec é um ponto de extremidade de comando / api. É uma função separada, não opções para a função de criação de contêiner.

Já existem algumas maneiras de fazer isso com o Compose (https://github.com/docker/compose/issues/1809#issuecomment-128059030). onrun já existe. É command .

Com relação ao problema específico de despejar ou carregar dados de um banco de dados, essas são mais tarefas do tipo "fluxo de trabalho" ou "automação de construção", que geralmente são feitas em um Makefile. Tenho feito o protótipo de uma ferramenta exatamente para esses casos de uso chamada dobi , que executa todas as tarefas em contêineres. Também se integra muito bem com o Compose. Você pode estar interessado em experimentá-lo se não estiver satisfeito com Makefiles. Estou trabalhando em um exemplo de caso de uso de inicialização / carga de banco de dados.

@dnephin onrun não é um simples command porque você simplesmente perde a idempotência.

Vamos imaginar. create na criação do contêiner e nunca será executado novamente (despejar e restaurar).

exec:
    create:
        - echo baby
    destroy:
        - echo keny
    start:
        - echo start
    stop:
        - echo bye

Se você precisar de mais exemplos:

Obrigado pelo dobi, mas se você precisa criar uma ferramenta para melhorar a composição, a composição é ruim e é melhor usar uma ferramenta mais poderosa.

mas se você precisar criar uma ferramenta para aprimorar a composição, a composição é ruim e é melhor usar uma ferramenta mais poderosa.

É como dizer "se você precisa de aplicativos para melhorar seu sistema operacional, seu sistema operacional está ruim". Nenhuma ferramenta deve fazer tudo. A filosofia do Unix é fazer uma coisa e fazê-la bem . Isso é o que estamos fazendo aqui. O Compose faz sua única coisa "orquestrar contêineres para executar um aplicativo". Não é uma ferramenta de automação de construção.

É como dizer "se você precisa de aplicativos para melhorar seu sistema operacional, seu sistema operacional está ruim". Nenhuma ferramenta deve fazer tudo. A filosofia do Unix é fazer uma coisa e fazê-la bem. Isso é o que estamos fazendo aqui.

Nossa acho que chegamos da melhor má fé.

Infelizmente, um componente reutilizável simples não é como as coisas estão acontecendo. O Docker agora está construindo ferramentas para lançar servidores em nuvem, sistemas para clustering e uma ampla gama de funções: construção de imagens, execução de imagens, upload, download e, eventualmente, até rede de sobreposição, tudo compilado em um binário monolítico executado principalmente como root em seu servidor . O manifesto do contêiner padrão foi removido. Devemos parar de falar sobre contêineres Docker e começar a falar sobre a plataforma Docker. Não está se tornando o bloco de construção simples e compostável que tínhamos imaginado.

Portanto, você pode garantir que nunca veremos "docker compose" escrito em Go inside no docker monolithic binário para manter a filosofia unix? https://www.orchardup.com/blog/orchard-is-joining-docker

Para continuar em direção ao objetivo original, estamos entrando no Docker. Entre outras coisas, vamos continuar trabalhando para tornar o Docker a melhor experiência de desenvolvimento que você já viu - tanto com o Fig quanto incorporando as melhores partes do Fig ao próprio Docker.

Resumindo, não há como fazer coisas como carregar luminárias com compose ..? Devo dizer que estou surpreso ..
A maneira oficial é adicionar carregamento de fixação ao meu contêiner de produção? Ou escrever um script de shell em torno do meu arquivo de composição? No último caso, eu também poderia apenas executar 'docker run' como fiz antes.

@discordianfish , Se, de alguma forma, alguém acordasse para o fato de que engenheiros de CI / CD precisam ser capazes de lidar com eventos do ciclo de vida e orquestração pelo menos em um nível muito básico, então quem sabe docker / docker-compose pode realmente fazer seu saída de pipelines de desenvolvimento local e infraestrutura de teste e encontre um lugar em mais ambientes de produção. Tenho esperança de que quem está trabalhando nas pilhas resolva esses problemas, mas não vou prender a respiração.

Afinal, o que precisa ser feito em tempo de compilação pode ser diferente do que é necessário em tempo de execução e é necessário em tempo de execução, muitas vezes varia de acordo com o ambiente de implantação ...

É um trabalho chato informar meus scripts externos se um up vai criar ou iniciar contêineres ...

E essas são coisas em que alguns ganchos de ciclo de vida + comandos + variáveis ​​de ambiente podem ajudar.

Você vê isso em estruturas de gerenciamento de serviço e outras ferramentas de orquestração ... por que não em docker-compose?

Você pode estar interessado em https://github.com/dnephin/dobi , que é uma ferramenta em que venho trabalhando e que foi projetada para esses fluxos de trabalho.

@dnephin pare de

Obrigado pelo seu comentário construtivo. Não percebi que já havia mencionado dobi neste tópico há 8 meses.

Se você está feliz com o Makefile / bash, isso é ótimo! Estou feliz que seu problema foi resolvido.

Adicionou um comentário relacionado a este tópico aqui: https://github.com/docker/compose/issues/1341#issuecomment -295300246

@dnephin para este, meu comentário pode ser aplicado:

É tão triste que este problema tenha sido fechado devido a alguma refratariedade à evolução: desapontado:

O maior valor de ter docker compose é a padronização

Essa é a questão. Se pudéssemos "apenas" escrever um arquivo .sh ou qualquer outra coisa para fazer o trabalho sem usar o Docker Compose, por que o Docker Compose existe? :confuso:

Podemos entender que é um grande trabalho, como @ shin- disse:

infelizmente, é um fardo muito grande para apoiar nessa fase do projeto

:coração:

Mas você não pode dizer "Faça um script", o que significa "Ei, isso é muito difícil, não vamos conseguir".

Se for difícil de fazer, basta dizer "Sua ideia é interessante e atende a algumas necessidades, mas é realmente difícil de fazer e não temos recursos para fazer no momento ... Talvez você possa desenvolvê-la e perguntar uma solicitação de pull "ou algo assim: lâmpada:

Em # 1341, eu "apenas" vejo uma maneira de escrever em docker-compose.yml comandos como nmp install que seriam executados antes ou depois de alguns eventos (como a criação de contêineres), como você faria com docker exec <container id> npm install por exemplo.

Caso de uso

Eu tenho uma imagem NodeJS personalizada e quero executar npm install no contêiner criado a partir dela, com um docker-compose up --build .

Meu problema é: o código do aplicativo não é adicionado ao contêiner, ele é montado nele com um volume, definido em docker-compose.yml :

custom-node:
    build: ../my_app-node/
    tty: true
    #command: bash -c "npm install && node"
    volumes:
     - /var/www/my_app:/usr/share/nginx/html/my_app

portanto, não posso executar npm install no Dockerfile porque ele precisa do código do aplicativo para verificar as dependências. Descrevi o comportamento aqui: http://stackoverflow.com/questions/43498098/what-is-the-order-of-events-in-docker-compose

Para executar npm install , tenho que usar uma solução alternativa, a instrução command :

command: bash -c "npm install && node"

que não é realmente limpo: desapontado: e que não consigo executar nas versões Alpine (eles não têm o Bash instalado).

Achei que o Docker Compose forneceria uma maneira de executar comandos exec em contêineres, por exemplo:

custom-node:
    build: ../my_app-node/
    tty: true
    command: node
    volumes:
     - /var/www/my_app:/usr/share/nginx/html/my_app
    exec:
     - npm install

Mas não está, e acho que está faltando mesmo!

Eu esperava que o compose fosse projetado para teste, mas provavelmente estou errado e é mais voltado para o desenvolvimento local, etc. Encontrei várias outras arestas como contêineres órfãos e a relação pouco clara entre o nome do projeto, o caminho e como ele é usado para identificar a propriedade, o que acontece se você tiver vários arquivos de composição no mesmo diretório etc. etc. Portanto, no geral, não parece uma boa opção para CI.
Em vez disso, estou planejando reutilizar meus manifestos de produção k8s em CI executando o kubelet autônomo. Isso também exigirá muita cola, mas pelo menos assim posso usar as mesmas declarações para dev, test e prod.

@ lucile-sticky você pode usar sh -c em alpino.

Parece que o que você quer é "automação de compilação", que não é função do docker-compose. Você já olhou para dobi ?

Duas questões:

  • Por que essa não é a função do Docker Compose?
  • Se o objetivo é ter apenas uma ferramenta para governar todos eles, por que eu usaria outra ferramenta para concluir uma tarefa que o Docker Compose não é capaz de fazer?

Esse recurso é altamente necessário!

@ lucile-sticky

Por que essa não é a função do Docker Compose?

Porque a função do Compose está claramente definida e não inclui essas funções.

Compose é uma ferramenta para definir e executar aplicativos Docker de vários contêineres. Com o Compose, você usa um arquivo Compose para configurar os serviços do seu aplicativo. Então, usando um único comando, você cria e inicia todos os serviços de sua configuração

Se o objetivo é ter apenas uma ferramenta para governar todos, por que eu usaria outra ferramenta para concluir uma tarefa que o Docker Compose não é capaz de fazer?

Não queremos ser a única ferramenta para governar todos eles. Seguimos a filosofia UNIX e acreditamos em "fazer com que cada programa faça bem uma coisa. Para fazer um novo trabalho, crie de novo em vez de complicar os programas antigos adicionando novos recursos."
Não há problema em discordar dessa filosofia, mas é assim que nós da Docker desenvolvemos software.

Eu crio esta edição, em agosto de 2015, a cada ano alguém adiciona um comentário e estamos repetindo as mesmas perguntas com as mesmas respostas (e com certeza você verá @dnephin fazendo um anúncio para sua ferramenta).

@canela-

Você não pode separar "construir" e "provisionar" nas ferramentas de orquestração.

Por exemplo, você pode conhecer um deles:

Ao configurar um serviço, você deve provisioná-lo. Se eu implantar um tomcat, tenho que provisioná-lo com um war, se eu criar um banco de dados, tenho que injetar dados, etc., não importa como o contêiner deve ser iniciado (deixe o mantenedor da imagem gerenciá-lo). O objetivo principal de um "provisionador" no caso do Compose é evitar mal-entendidos entre "o que inicia meu contêiner" e "o que é provisionado".

Como disse sua citação no documento de composição "Com o Compose, você usa um arquivo Compose para configurar os serviços de seu aplicativo. Em seguida , usando um único comando, você cria e inicia todos os serviços a partir de sua configuração"

Filosofia Unix? Deixe-me rir. Aponto a você a mesma resposta que dei nesta edição https://github.com/docker/compose/issues/1809#issuecomment -237195021.
Vamos ver como "moby" irá evoluir na filosofia Unix.

@ shin-docker-compose não adere à Filosofia do Unix por nenhum esforço da imaginação. Se docker-compose aderisse à filosofia Unix, haveria comandos discretos para cada um de build, up, rm, start, stop, etc e cada um teria um stdin, stdout e stderr utilizáveis ​​que se comportavam de forma consistente. diz o administrador de sistemas unix com mais de 20 anos de experiência, incluindo System V, HP-UX, AIX, Solaris e Linux

Vamos voltar para a visão geral para escrever

Compose é uma ferramenta para definir e executar aplicativos Docker de vários contêineres. Com o Compose, você usa um arquivo Compose para configurar os serviços do seu aplicativo. Então, usando um único comando, você cria e inicia todos os serviços de sua configuração.

Em última análise, docker-compose é uma ferramenta de orquestração para gerenciar um grupo de serviços com base em contêineres criados a partir de imagens docker. Suas funções principais são 'criar', 'iniciar', 'parar', 'dimensionar' e 'remover' serviços definidos em um arquivo docker-compose.yml.

Muitos serviços requerem que comandos adicionais sejam executados durante cada uma dessas transições do ciclo de vida. O dimensionamento de clusters de banco de dados geralmente requer a junção ou remoção de membros de um cluster. O dimensionamento de aplicativos da web geralmente requer a notificação de um balanceador de carga que você adicionou ou removeu um membro. alguns administradores de sistemas paranóicos gostam de liberar à força seus logs de banco de dados e criar pontos de verificação ao desligar seus bancos de dados.

A ação na transição de estado é necessária para a maioria das ferramentas de orquestração. Você o encontrará nas ferramentas da AWS, ferramentas do Google, capataz, chef, etc. a maioria das coisas que vivem neste espaço de orquestração tem algum tipo de gancho de ciclo de vida.

Eu acho que isso está firmemente dentro do alcance do docker-compose, já que é uma ferramenta de orquestração e está ciente das mudanças de estado. Não acho que eventos ou scripts externos se encaixem no caso de uso. Eles não são idempotentes, é muito mais difícil lançar um 'segundo' serviço ao lado de compor para acompanhar os eventos. Se os ganchos são executados dentro ou fora do contêiner, é um detalhe de implementação.

No final do dia, há uma necessidade real que está sendo expressa pelos usuários de docker-compose e @aanand , @dnephin , @ shin- parecem estar descartando isso. Seria bom ver isso incluído em um roteiro.

Este tipo de funcionalidade está atualmente bloqueando minha adoção do docker em minhas implantações de teste e produção de produção. Eu realmente gostaria que isso fosse tratado de alguma forma, em vez de descartado.

Acho que isso vai ser muito útil!

Para mim, o problema é que quando há um contêiner de aplicativo A executando o serviço 'a' dependente do contêiner B do banco de dados executando o serviço b. Então, um contêiner falha a menos que seu b seja configurado.
Eu preferiria usar imagens docker hub em vez de reescrever meus próprios Dockerfiles. Mas isso significa que A falha e nenhum contêiner é criado. A única opção é

  1. Use B como imagem base e crie meu próprio Dockerfile.
  2. Deixe A falhar e configure b no script e reinicie A.

Eu tenho exatamente o mesmo caso de uso que @ lucile-sticky.

@lekhnath para o meu caso, resolvi editando a opção command em meu docker-compose.yml :

command: bash -c "npm install && node"

Mas é tãããão feio TT

@ lucile-sticky Deve-se notar que isto anula qualquer comando definido em Dockerfile do contêiner. Eu contornei isso montando um script de shell personalizado usando volumes , fazendo com que command em meu arquivo Docker Compose executasse esse script e incluindo nele o CMD do Dockerfile .

Por que este problema foi encerrado? _escrever um script bash_ ou _usar esta ferramenta que escrevi_ não é um motivo válido para encerrar este problema.

Este é um recurso muito útil e importante que é necessário em muitos casos de uso em que a composição é usada.

@dnephin Você acha que a execução de scripts init está fora do escopo de implantações de aplicativos baseados em contêiner? afinal, a composição é sobre "definir e executar aplicativos de vários contêineres com o Docker".

Alguém deu uma olhada no dobi se você não fez isso aqui está :)
image

Supondo que nada nunca aconteceu com isso. Eu adoraria ver algum tipo de funcionalidade dentro do arquivo docker-compose onde poderíamos escrever quando um comando deve ser executado, como o exemplo dado por @ ahmet2mir .

Muito triste ver esse recurso não sendo implementado.

Implemente este recurso, preciso instalar automaticamente os arquivos após docker-compose up, pois as pastas onde o arquivo deve ser copiado são criadas após a inicialização dos containers.
obrigado

É incrível que esse recurso ainda não tenha sido implementado!

Este é um formulário muito pobre de @dnephin. Você inibiu a implementação de um recurso tão procurado para o que parece principalmente autopromoção, e você nem mesmo está disposto a continuar a conversa.

Sinto muito, não consegui pensar em uma linguagem mais suave para colocá-lo, a falta desse recurso acrescentou fração ao nosso fluxo de trabalho, como muitos outros desenvolvedores e equipes, e você tem sido um obstáculo para resolver este problema.

Oh, vamos torná-lo o unix-way então.
_Just_ (multiplex então) canaliza docker-compose up stdin para CMD cada contêiner?
Para que esse arquivo yaml

services:
  node:
    command: sh -

faria este trabalho: cat provision.sh | docker-compose up
contêineres são para executar coisas, não vejo melhor uso de stdin do que passar comandos adiante.

Uma alternativa poderia ser:

services:
  node:
    localscript: provision.sh

Embora um pouco centrado em shell, isso resolveria 99% dos casos de uso de provisionamento.

Embora existam casos de uso válidos e muitos votos positivos sobre isso ... aparentemente, ele foi negado. É uma pena que eu, como muitos outros aqui, ache isso extremamente útil.

Adicionando meu +1 à grande pilha de +s existentes

... outro +1 aqui!

Acho que se existe esse pedido para esse recurso deve ser implementado, as ferramentas estão aqui para nos ajudar a alcançar nossos objetivos e devemos moldá-las para nos ajudar a não dificultar nossa vida.
Eu entendo a filosofia à qual alguém adere, mas adicionar algum tipo de "comandos ganchos" não deve ser um problema.

+1 +1

Enquanto espero por esse recurso, uso o seguinte script para realizar uma tarefa semelhante:

docker-start.sh

#!/usr/bin/env bash

set -e
set -x

docker-compose up -d
sleep 5

# #Fix1: Fix "iptable service restart" error

echo 'Fix "iptable service restart" error'
echo 'https://github.com/moby/moby/issues/16137#issuecomment-160505686'

for container_id in $(docker ps --filter='ancestor=reduardo7/my-image' -q)
  do
    docker exec $container_id sh -c 'iptables-save > /etc/sysconfig/iptables'
  done

# End #Fix1

echo Done

@ reduardo7 Então você pode muito bem descartar o docker-compose, dessa forma você terá uma dependência a menos.

@omeid , você está certo! É uma solução alternativa para executar uma tarefa semelhante, desculpe!

@ reduardo7 Não precisa se desculpar, o que você postou provavelmente será útil para algumas pessoas.
Eu estava apenas apontando que o problema original ainda está de pé e não deveria ter sido encerrado. :)

Eu entendo que os estandes do

No entanto, se esses padrões são usados ​​com frequência, que tal apresentar um guia (ou algum teste) para que outros possam usá-lo facilmente?

Parece não haver discordância de que esse padrão pode ser usado com frequência.

@MaybeS A única discordância é que @dnephin prefere ver sua ferramenta

@omeid sim, de fato.

exemplo de hoje de querer uma maneira de escrever para fazer alguma forma de onrun

version: "3.3"
services:
  gitlab:
    image: 'gitlab/gitlab-ce:latest'
    restart: always
    hostname: 'gitlab'
    environment:
      GITLAB_OMNIBUS_CONFIG: |
        # NOTE: this URL needs to be right both for users, and for the runner to be able to resolve :() - as its the repo URL that is used for the ci-job, and the pull url for users.
        external_url 'http://gitlab:9090'
        gitlab_rails['gitlab_shell_ssh_port'] = 2224
    ports:
      - '9090:9090'
      - '2224:22'
  gitlab-runner:
    image: gitlab/gitlab-runner:latest
    volumes:
    - /var/run/docker.sock:/var/run/docker.sock

e, claro, o corredor não está registrado - e para fazer isso, precisamos

  1. retire o token do banco de dados no gitlab
  2. execute o registro no contêiner do runner

então, em vez de definir a implantação do meu aplicativo multi-contêiner apenas em docker-compose, preciso usar alguns meios secundários - neste caso ... docs?

export GL_TOKEN=$(docker-compose exec -u gitlab-psql gitlab sh -c 'psql -h /var/opt/gitlab/postgresql/ -d gitlabhq_production -t -A -c "SELECT runners_registration_token FROM application_settings ORDER BY id DESC LIMIT 1"')
docker-compose exec gitlab-runner gitlab-runner register -n \
  --url http://gitlab:9090/ \
  --registration-token ${GL_TOKEN} \
  --executor docker \
  --description "Docker Runner" \
  --docker-image "docker:latest" \
  --docker-volumes /var/run/docker.sock:/var/run/docker.sock \
  --docker-network-mode  "network-based-on-dirname-ew_default"

mmm, talvez eu consiga hackear algo, onde tenho outro contêiner que tem o soquete docker e docker exec's

aposto que existe uma maneira ....

por exemplo, posso adicionar:

  gitlab-initializer:
    image: docker/compose:1.18.0
    restart: "no"
    volumes:
    - /var/run/docker.sock:/var/run/docker.sock
    - ./gitlab-compose.yml:/docker-compose.yml
    entrypoint: bash
    command: -c "sleep 200 && export GL_TOKEN=$(docker-compose -p sima-austral-deployment exec -T -u gitlab-psql gitlab sh -c 'psql -h /var/opt/gitlab/postgresql/ -d gitlabhq_production -t -A -c \"SELECT runners_registration_token FROM application_settings ORDER BY id DESC LIMIT 1\"') && docker-compose exec gitlab-runner gitlab-runner register -n --url http://gitlab:9090/ --registration-token ${GL_TOKEN} --executor docker --description \"Docker Runner\" --docker-image \"docker:latest\" --docker-volumes /var/run/docker.sock:/var/run/docker.sock --docker-network-mode  \"simaaustraldeployment_default\""

ao meu arquivo de composição - embora eu precise de algum tipo de loop / espera, pois o gitlab não está pronto imediatamente - sleep 200 pode não ser suficiente.

então - você __pode__ hackear algum tipo de padrão como este diretamente em um docker-compose.yml - mas pessoalmente, prefiro um suporte mais limpo do que este :)

@SvenDowideit onrun já existe, é entrypoint ou cmd .

O script do entrypoint para esta imagem fornece até mesmo um gancho para você. $GITLAB_POST_RECONFIGURE_SCRIPT pode ser definido como o caminho de um script que será executado após a conclusão de toda a configuração (consulte /assets/wrapper na imagem). Defina a variável env para o caminho do seu script que faz o registro do psql + e pronto.

Mesmo que a imagem não forneça esse gancho, é algo que pode ser adicionado facilmente estendendo a imagem.

embora eu precise de algum tipo de loop / espera, já que o gitlab não está pronto imediatamente - sleep 200 pode não ser suficiente.

Isso seria necessário mesmo com uma opção "exec-after-start". Como o script do entrypoint realmente fornece um gancho, acho que provavelmente não é necessário com essa solução.

não, eu (acho) que você perdeu uma parte do problema que estou mostrando:

no meu caso, preciso acessar os dois contêineres, não apenas um - portanto, o ponto de entrada / comando _não_ me dá isso.

GL_TOKEN vem do contêiner gitlab e é usado no contêiner gitlab-runner para registrar.

então o hack que estou fazendo é usar a imagem docker/compose para adicionar um terceiro contêiner - isso não é algo para o qual você possa modificar a configuração / ponto de entrada / configurações de um contêiner e é um exemplo inteiramente (trivial) de um coordenação de vários contêineres que precisa de mais.

Tenho trabalhado em coisas para torná-los um pouco mais mágicos - o que basicamente significa que meu contêiner de inicialização tem alguns loops de sono, já que leva algum tempo para o gitlab se inicializar.

TBH, estou começando a sentir que usar um script, rodando em um init-container que usa o próprio arquivo de composição e a imagem docker / compose, _é_ a maneira certa de esconder esse tipo de complexidade - para a não produção "tente me fora, e isso vai funcionar "em situações como esta.

_IF_ eu deveria considerar algum açúcar sintático estranho para ajudar, talvez eu optasse por algo como:

gitlab-initializer:
    image: docker/compose:1.18.0
    restart: "no"
    volumes:
    - /var/run/docker.sock:/var/run/docker.sock
    - ./gitlab-compose.yml:/docker-compose.yml
    entrypoint: ['/bin/sh']
    command: ['/init-gitlab.sh']
    file:
      path: /init-gitlab.sh
      content: |
            for i in $(seq 1 10); do
                export GL_TOKEN=$(docker-compose -f gitlab-compose.yml -p sima-austral-deployment exec -T -u gitlab-psql gitlab sh -c 'psql -h /var/opt/gitlab/postgresql/ -d gitlabhq_production -t -A -c "SELECT runners_registration_token FROM application_settings ORDER BY id DESC LIMIT 1"')
                echo "$i: token($?) == $GL_TOKEN"
                ERR=$?

                if [[ "${#GL_TOKEN}" == "20" ]]; then
                    break
                fi
                sleep 10
            done
            echo "GOT IT: token($ERR) == $GL_TOKEN"

            for i in $(seq 1 10); do
                if  docker-compose -f gitlab-compose.yml  -p sima-austral-deployment exec -T gitlab-runner \
                    gitlab-runner register -n \
                    --url http://gitlab:9090/ \
                    --registration-token ${GL_TOKEN} \
                    --executor docker \
                    --description "Docker Runner" \
                    --docker-image "docker:latest" \
                    --docker-volumes '/var/run/docker.sock:/var/run/docker.sock' \
                    --docker-network-mode  "simaaustraldeployment_default" ; then
                        echo "YAY"
                        break
                fi
                sleep 10
            done

ou seja, como cloud-init: http://cloudinit.readthedocs.io/en/latest/topics/examples.html#writing -out-arbitrary-files

mas no final das contas - nós _temos_ uma solução para coordenar coisas complicadas de vários contêineres de dentro de um docker-compose-yml.

Se você puder definir um token predefinido, poderá fazê-lo a partir de um script de ponto de entrada em gitlab-runner . Não há como definir essa ponta de tempo?

@dnephin No momento em que você menciona o script, está

onrun não é o mesmo que entrypoint ou cmd .

O entrypoint / cmd é para configurar o executável que irá rodar como os containers init / PID 1.

A ideia mencionada neste e em muitos outros problemas relacionados é sobre init scripts , que é diferente de init no contexto de inicialização e é sobre scripts de inicialização de aplicativo, pense na configuração do banco de dados.

@dnephin provavelmente seria mais útil se você se concentrasse no conjunto de problemas geral, em vez de tentar contornar os problemas de um conjunto de contêineres específicos.

Pelo que tenho visto, não, é um segredo gerado - mas na realidade, este não é o único requisito de coordenação de vários contêineres que, mesmo neste pequeno sistema de jogo, é provável que tenha - é apenas o mais rápido para mim protótipo em público.

Como é possível substituir entrypoint e command em um arquivo de composição desde a v1 (https://docs.docker.com/compose/compose-file/compose-file -v1 / # entrypoint) e ainda não tem uma diretiva como onrun para executar um comando quando os contêineres estão ativos?

TBH, eu realmente não acho que onrun seja plausível - Docker, ou o orquestrador não sabe o que significa "contêineres todos ativos" - em um dos meus casos, o HEALTHCHECK irá falhar, até que eu faça algumas "coisas" extras onde eu obtenho informações de um contêiner e as utilizo para chutar algumas outras coisas em outros contêineres.

E _se_eu groco certo, isso significa que basicamente estou precisando de um container Operator, que contém o código que detecta quando algumas partes do sistema multi-container estão prontas o suficiente para fazer parte do trabalho, (enxágue e repita), até ou ele completou seu trabalho e sai, ou talvez até monitora as coisas e as conserta.

E isso me parece um trabalho que é melhor resolvido (em docker-compose) por um contêiner docker-compose com código.

Provavelmente, vou brincar com a forma de converter esse operador em algo que possa lidar com as pilhas docker swarm (devido a outras necessidades do projeto).

Não tenho certeza se há muito açúcar sintático que pode ser adicionado ao docker-compose, a menos que seja algo como marcar um contêiner como "este é um operador, dê a ele habilidades mágicas".

É claramente visto que os desenvolvedores não querem ouvir os usuários .. Vou olhar para outra ferramenta ... docker-compose é uma grande dor .. Eu não entendo porque você não consegue entender que a única coisa útil que vem do docker-composer é uma ferramenta de construção ... Passei muito tempo pesquisando COMO posso executar o comando SIMPLE para adicionar permissões dentro de um contêiner para o usuário ativo ..

Parece que docker-composer simplesmente NÃO ESTÁ FEITO ...

Eu também quero algo que onrun no meu arquivo de composição

__BUT__, nem contêineres, nem composição tem uma maneira de saber o que onrun significa. É por isso que o padrão do operador existe e porque fiz os exemplos em https://github.com/docker/compose/issues/1809#issuecomment -362126930

__é__ possível fazer isso hoje - em essência, você adiciona um serviço onrun que espera até que quaisquer outros serviços estejam realmente prontos para interagir (no caso do gitlab, isso leva um pouco de tempo), e então faz tudo o que você precisa fazer para coordenar as coisas.

Se _existe_ algo que não funciona com isso, diga-nos, e veremos se podemos descobrir algo!

Eu também quero algo que será executado no meu arquivo de composição

MAS, nem containers, nem compose têm uma maneira de saber o que significa onrun.

A meu ver, onrun por serviço significa quando o primeiro processo de contêiner começa. Em um grande número de casos, o contêiner está executando apenas um processo, pois essa é a maneira recomendada de executar os contêineres.

O problema de suporte de plataforma cruzada foi resolvido anteriormente, já que o comando pode ser completamente independente do SO por meio de docker exec , da mesma forma que RUN não precisa significar um comando Linux no Dockerfile.
https://docs.microsoft.com/en-us/virtualization/windowscontainers/manage-docker/manage-windows-dockerfile

Ainda esperando pelo recurso onrun

Eu preciso desses onrun recursos também, pensei que estava nesta ferramenta. Por causa desse recurso que falta agora eu preciso manter 2 scripts cara.

Pessoal, e se eu fizesse um invólucro em torno desse docker-compose e permitisse esse onrun recurso? Vocês usariam isso?

@wongjiahau pode ser algo assim? https://github.com/docker/compose/issues/1809#issuecomment -348497289

@ reduardo7 Sim, pensei em docker-composei , e com o docker-composei.yml que contém o atributo onrun .
A propósito, docker-composei significa docker-compose improved .

A solução real provavelmente é construir uma imagem do 'Orquestrador' que execute e gerencie (por meio de scripts bash) as 'Imagens do aplicativo' (possivelmente usando o docker) internamente. Caso contrário, estaremos sempre pedindo mais recursos para uma ferramenta que "não foi feita para fazer o que queremos".

Portanto, devemos até considerar o Docker dentro do Docker ...

apenas para adicionar meu apoio a este recurso proposto. onrun faz sentido, mas para ampliar um pouco a utilidade potencial e torná-la uma prova futura, talvez alguém precise olhar para uma arquitetura 'onevent' mais ampla, uma das quais seria onrun.

Dada a direção predominante para que os contêineres sejam autocontidos, um serviço por contêiner, o contêiner deve ser autossuficiente em termos de reconhecimento de contexto operacional. O que flui desse arquivo de composição deve ser o meio para defini-lo, não os scripts bolt-on. É difícil argumentar contra isso, a menos que você seja um fanático egoísta.

No meu caso, meus contêineres redis carregam scripts Lua depois que o servidor redis é iniciado. Em um ambiente normal sem container, faço o systemd executar um script pós-inicialização. Simples e consistente com a arquitetura do systemd. Deve existir um princípio semelhante para a composição, dada sua função na configuração do contexto para a execução dos contêineres.

Como um conselho geral para os mantenedores, concentre-se em princípios operacionais comprovados e não em preferências pessoais.

então a solução (depois de ler todo este tópico) é usar um script bash para fazer o trabalho ... nesse caso, removerei docker-compose (podemos fazer tudo com o docker cmd ...)

thx dev para ouvir as pessoas que estão usando suas coisas :)

Ao ver a quantidade de mensagens contendo argumentos e contra-argumentos lutando contra proposições simples (como ter um evento onrun ), minha primeira impressão honesta é que o Github Issues se tornou um lugar onde _doprietários_ (desenvolvedores de projetos) mostram seus egos e inteligência por meio do uso seu conhecimento e argônio técnico para se opor à contribuição inteligente dos usuários.

Por favor, vamos tornar o Código Aberto verdadeiramente _aberto_.

alguma atualização sobre este recurso? qual é o problema?

@ v0lume ,

Ainda não parece haver uma solução ... No entanto, gostaria de compartilhar uma solução alternativa.
Ao especificar a versão "2.1" no docker-compose.yml, você pode abusar do teste de verificação de integridade para executar código adicional dentro da imagem quando ela for iniciada. Aqui está um exemplo:

version: '2.1'
services:
    elasticsearch:
        image: docker.elastic.co/elasticsearch/elasticsearch:5.4.3
        healthcheck:
            test: |
                curl -X PUT elasticsearch:9200/scheduled_actions -H "ContentType: application/json" -d '{"settings":{"index":{"number_of_shards":'1',"number_of_replicas":'0'}}}' &&
                curl --silent --fail localhost:9200/_cat/health ||
                exit 1
            interval: 11s 
            timeout: 10s 
            retries: 3
        environment:
            - discovery.type=single-node
            - ES_JAVA_OPTS=-Xms1g -Xmx1g
            - xpack.security.enabled=false
    main:
        image: alpine
        depends_on:
            elasticsearch:
                condition: service_healthy

Se o script healthcheck-test que você escreve sair com código> = 1, ele pode ser executado várias vezes.
A verificação de integridade de um serviço só será executada se outro serviço depender dele e especificar a condição service_healthy conforme visto no exemplo.

Gosto da abordagem @ T-vK e já a usei com sucesso antes. Mas eu gostaria de compartilhar outro ... hack:

# Run Docker container here

until echo | nc --send-only 127.0.0.1 <PORT_EXPOSED_BY_DOCKER>; do
  echo "Waiting for <YOUR_DOCKER> to start..."
  sleep 1
done

# Do your docker exec stuff here

+1
Concordo totalmente com isso porque o recurso é necessário e já foi implementado por outros orquestradores do docker, como o kubernetes. Ele já tem ganchos de ciclo de vida para contêineres e está documentado aqui .

Mas deixe-me contribuir com um caso de uso que você não pode resolver com Dockerfiles.

Digamos que você precise montar um volume em tempo de execução e criar um link simbólico de seu contêiner para o volume sem saber previamente o nome exato do diretório. Tive um caso em que o nome do dir era dinâmico dependendo do ambiente em que estava implantando e o estava passando como uma variável.

Claro que encontrei uma solução alternativa para isso e há mais de uma. Por outro lado, os ganchos me dariam a flexibilidade e uma abordagem melhor para fazer alterações dinamicamente sem a necessidade de hackear coisas e substituir o Dockerfile.

Estou feliz por ter encontrado esse problema. Tenho brincado com o Docker e a composição do Docker há alguns anos. Agora, seriamente, esperava usá-lo como uma ferramenta para começar a dimensionar um sistema. Vou verificar novamente a cada um ou dois anos, mas com base na atitude dos mantenedores do projeto, vou simplesmente sobreviver usando scripts ou alguma outra ferramenta. Fico feliz por não ter investido muito tempo e descoberto isso logo no início.

Dica profissional: se alguém que está apenas começando a mudar seu fluxo de trabalho para este tipo de ferramenta já precisa do que está descrito aqui, pode valer a pena repensar sobre 'por que' você está construindo isso. Sim, você tem sucesso, mas é porque as pessoas usaram a coisa em primeiro lugar e você provavelmente estava superaberto para dar a elas o que elas precisavam.

Muito bem sucedida.

Posso te dar o que você quiser (exceto minha namorada) se esse recurso for implementado e eu serei a pessoa mais feliz em todo o universo :)

apenas para adicionar meu apoio a este recurso proposto. onrun faz sentido, mas para ampliar um pouco a utilidade potencial e torná-la uma prova futura, talvez alguém precise olhar para uma arquitetura 'onevent' mais ampla, uma das quais seria onrun.

Isso seria ótimo.

Para adicionar a isso, dado o seguinte:

services:
    web:
        image: node:8-alpine
        depends_on:
            - db
    db:
        image: postgres:alpine
        onrun: "echo hi"

seria demais adicionar scripts de eventos cruzados?

    web:
        events:
            db_onrun: "connectAndMigrate.sh"

Na minha opinião, adicionar isso ao docker-compose é simples, não só para você, que está usando o compose file e compose stack, mas também para outros desenvolvedores em sua equipe.

  • Usando contêineres separados - todos devem saber que devem executá-los.
  • Escreva Dockerfile personalizado - temos cerca de 20 serviços e, para cada serviço, devo substituir o Dockerfile para executar algum comando.

Precisamos instalar e configurar mkcert , por exemplo, em cada ambiente para ter certificados confiáveis. Não faz parte do contêiner ou Dockerfile, pois não é necessário no estágio / produção. Qual é a abordagem adequada aqui para instalar a ferramenta e todos que estão usando o arquivo de composição não têm ideia do que está acontecendo nos bastidores?

Adicionar outro caso de uso:

É necessária uma instância do wordpress. Escrevi meu docker-compose.yaml. docker-compose up - Ops! Preciso definir as permissões de arquivo do diretório de plug-ins ... Não consigo encontrar nenhuma outra maneira de fazer isso funcionar, preciso definir as permissões depois que o contêiner estiver em execução porque estou vinculando alguns arquivos do host e parece ser a única maneira para consertar as permissões fs é feito chown -Rf www-data.www-data /var/www/wp-content de dentro do contêiner. Escrever meu próprio Dockerfile e construir, apenas para isso? Isso parece estúpido para mim.

Felizmente para mim, o hack healthcheck fornecido acima me permitiu implementar isso. Vejo outras páginas na web falando sobre a questão das permissões de configuração nos volumes do docker, mas as soluções sugeridas não funcionaram.

Fico feliz em ver que esses porteiros, @dnephin , @aanand , @ shin-, estão recebendo uma tonelada de calor por isso. Realmente fala muito quando uma comunidade inteira grita o mais alto possível, e os desenvolvedores principais apenas sentam-se, se mantêm e se recusam a ouvir. Tão típico também. Vamos contar não apenas o número de polegares para cima, mas também os 34 usuários que responderam dizendo que isso é necessário:
01) sshishov
02) fescobar
03) sandor11
04) web-ted
05) v0lume
06) webpolis
07) Skull0ne
08) usergoodvery
09) wongjiahau
10) MFQ
11) Yosefrow
12) bagermen
13) daqSam
14) omeid
15) dantebarba
16) willyyang
17) SharpEdgeMarshall
18) transportadora perdida
19) fantasma
20) rodrigorodriguescosta
21) datatypevoid
22) dextermb
23) lekhnath
24) lucile-sticky
25) rav84
26) dopar
27) ahmet2mir
28) montera82
29) discordianfish
30) jasonrhaas
31) fferraris
32) hipergig
33) sunsided
34) sthulb

E o número que disse não? Um 3 colossal:
01) dnephin
02) aanand
03) shin-

Hmmm ... 34 a 3 ...

@ rm-rf-etc boas análises ... Eu nem acho que @dnephin ou @aanand estão mais trabalhando no docker-compose. Com sorte, o Docker está planejando descontinuar a composição em favor das pilhas e não haverá uma equipe deixada aqui para reclamar e começaremos a ver o progresso do produto novamente.

Adicionar outro caso de uso:

É necessária uma instância do wordpress. Escrevi meu docker-compose.yaml. docker-compose up - Ops! Preciso definir as permissões de arquivo do diretório de plug-ins ... Não consigo encontrar nenhuma outra maneira de fazer isso funcionar, preciso definir as permissões depois que o contêiner estiver em execução porque estou vinculando alguns arquivos do host e parece ser a única maneira para consertar as permissões fs é feito chown -Rf www-data.www-data /var/www/wp-content de dentro do contêiner.

Nesse caso, você também pode definir a propriedade user em seu arquivo de composição

Escrever meu próprio Dockerfile e construir, apenas para isso? Isso parece estúpido para mim.

Parece que você formou uma opinião forte; mas, realisticamente, não haveria nada de "estúpido" em escrever um Dockerfile para modificar uma imagem de base para atender às suas necessidades. Essa é a intenção original de todas as imagens básicas.

Felizmente para mim, o hack healthcheck fornecido acima me permitiu implementar isso. Vejo outras páginas na web falando sobre a questão das permissões de configuração nos volumes do docker, mas as soluções sugeridas não funcionaram.

Fico feliz em ver que esses porteiros, @dnephin , @aanand , @ shin-, estão recebendo uma tonelada de calor por isso.

Sim, boa atitude, companheiro. : D


@ rm-rf-etc boas análises ... Eu nem acho que @dnephin ou @aanand estão mais trabalhando no docker-compose.

Sim, já se passaram alguns anos - não há necessidade de repetir problemas antigos.

Com sorte, o Docker está planejando descontinuar a composição em favor das pilhas e não haverá uma equipe deixada aqui para reclamar e começaremos a ver o progresso do produto novamente.

🙄

@ shin- mas você acabou de enviar um ping com essa resposta

Recentemente, encontrei esse problema novamente e, embora isso possa ser feito conforme visto na minha solução alternativa , isso só funciona se você especificar 2.1, o que é péssimo.

É simplesmente espantoso para mim que a posição oficial pareça ser a de que você deve criar suas próprias imagens do docker para tudo.
Para mim, isso é literalmente como dizer "Se você quiser alterar uma configuração em qualquer programa, você deve modificar o código-fonte e recompilá-lo.".
Cada vez que você adiciona um novo serviço ou deseja atualizar para uma versão mais recente de .. por exemplo, a imagem MongoDB ou MySQL Docker, você teria que fazer um novo Dockerfile, compilá-lo e potencialmente colocá-lo em seu registro.
Isso é uma enorme perda de tempo e recursos em comparação com como seria se você pudesse apenas alterar image: mongo:3.0.2 para image: mongo:3.0.3 em seu docker-compose.yml.
Não estou falando sobre longos tempos de construção, estou falando sobre o fato de que você tem que se preocupar com Dockerfiles e docker build quando tudo o que você quer é atualizar ou alterar um parâmetro de um serviço que potencialmente não é igual destina-se a ser usado como uma imagem de base.

E o argumento de que todo aplicativo deve fazer uma coisa e apenas uma coisa realmente fede também. Não se trata de implementar um recurso totalmente novo, mas apenas de passar outro parâmetro para docker . Também levanta a questão de por que docker run , docker build , docker exec , docker pull etc. são todos parte do mesmo aplicativo. O argumento parece meio hipócrita agora, não é?

@ shin-, segui seu link e não vejo como a propriedade do usuário é relevante para definir o proprietário de um diretório montado por bind. Parece estar relacionado a portas.

Re: atitude: parece que as pessoas concordam comigo, então considere isso como um feedback forte. Desculpe se você não gosta de como estou expressando isso, mas realmente parece que as demandas do usuário estão sendo ignoradas, então o que mais você esperava?

Eu vim aqui esperando uma funcionalidade como o onrun: sendo sugerido porque estou apenas dois dias usando o compose e para mim uma ferramenta como esta deve ter essa funcionalidade.

Voltar aos meus arquivos do docker para atualizar cada um com um script separado para os recursos parece redundante. Eu apenas quero injetar um token de outro contêiner em uma variável de ambiente onde meu dockerfile era flexível antes agora está fortemente acoplado ao docker-composer.yml e à solução para um propósito simples.

Droga, eu li o tópico inteiro pulando para encontrar a resposta "ok pessoal, finalmente percebemos que isso é legal e vamos implementá-lo". É triste ver que isso não avançou.
+1 para começar!

@fabiomolinar , existe um tipo de solução, que usamos extensivamente em nossos enxames de produção, mas não é tão bom quanto ter um evento.

Usamos a seguinte âncora

#### configure a service to run only a single instance until success
x-task: &task
  # for docker stack (not supported by compose)
  deploy:
    restart_policy:
      condition: on-failure
    replicas: 1
  # for compose (not supported by stack)
  restart: on-failure

repetir tarefas até que tenham sucesso. Criamos contêineres para migrações e configurações de tarefas que têm resultados idempotentes e os executamos assim em nossa composição local e em nossas pilhas.

O serviço que depende da tarefa precisa falhar um pouco normalmente se o trabalho de configuração não for concluído. Na maioria dos casos, contanto que você não tenha problemas com alguns erros para os usuários finais, isso oferece uma consistência eventual que funcionará bem na maioria dos ambientes.

Também pressupõe que seus contêineres de serviço podem funcionar com os estados de conclusão de tarefa antes e depois. Em casos de uso como migrações de banco de dados, os serviços dependentes devem ser capazes de trabalhar com esquemas pré e pós-migração. Obviamente, algum pensamento deve ser colocado na coordenação de desenvolvimento e implantação, mas isso é um fato geral da vida para quem é fazendo atualizações contínuas de serviços.

@fabiomolinar , aqui está um exemplo de como usamos essa abordagem em nossos serviços de composição ...

#### configure a service to run only a single instance until success
x-task: &task
  # for docker stack (not supported by compose)
  deploy:
    restart_policy:
      condition: on-failure
    replicas: 1
  # for compose (not supported by stack)
  restart: on-failure

#### configure a service to always restart
x-service: &service
  # for docker stack (not supported by compose)
  deploy:
    restart_policy:
      condition: any
  # for compose (not supported by stack)
  restart: always

services: 
  accounts: &accounts
    <<: *service
    image: internal/django
    ports:
      - "9000"
    networks:
      - service
    environment:
      DATABASE_URL: "postgres://postgres-master:5432/accounts"
      REDIS_URL: "hiredis://redis:6379/"

  accounts-migrate:
    <<: *accounts
    <<: *task
    command: ./manage.py migrate --noinput

Obrigado por apontar isso @dopry. Mas meu caso era um pouco mais simples. Eu precisava colocar meu servidor em execução e então, somente depois de estar instalado e funcionando, eu precisava fazer algumas tarefas de implantação. Hoje descobri uma maneira de fazer isso realizando alguns pequenos processos de gerenciamento em uma única linha CMD . Imagine que os processos de servidor e implantação são chamados de server e deploy , respectivamente. Então usei:

CMD set -m; server $ deploy && fg server

A linha acima ativa o modo de monitor do bashes, então inicia o processo server em segundo plano, então executa o processo deploy e, finalmente, traz o processo server para o primeiro plano novamente para evitar que Docker mate o contêiner.

Enquanto discutimos isso, alguém tem alguma dica sobre como executar um comando no contêiner ou no host ao executar docker-compose up ?

Eu entendo que executar qualquer comando no host comprometeria as camadas de segurança, mas eu gostaria apenas de rm um diretório antes ou durante a inicialização de um contêiner. O diretório pode ser acessado no host e no contêiner. Não quero fazer uma imagem Docker personalizada ou ter um script que primeiro rm e depois execute docker-compose .

Obrigado!

@fabiomolinar , A abordagem que sua proposta viola alguns princípios de aplicativo de 12 fatores . Se você estiver organizando sua infraestrutura em contêineres, recomendo fortemente que os siga rigorosamente.

Alguns problemas que podem surgir de sua abordagem

  1. inicialização lenta do contêiner.
  2. ao dimensionar um serviço com o contêiner, o deploy será executado uma vez para cada instância, podendo levar a alguns problemas interessantes de simultaneidade.
  3. mais difícil classificar os registros da 'tarefa' e serviço para gerenciamento e depuração.

No início, achei a abordagem que estou recomendando contra-intuitiva. Funcionou bem na prática em nossos ambientes de desenvolvimento local em docker-compose, docker swarms e mesos / clusters de maratona. Também é eficaz para contornar a falta de 'onrun'.

A abordagem que usei é realmente muito feia. Usei-o por um tempo apenas para colocar meu ambiente de desenvolvimento em execução. Mas já mudei isso para usar scripts do entrypoint e o comando at para executar scripts depois que o servidor estiver instalado e funcionando. Agora meu container está rodando com o processo correto como o PID 1 e respondendo a todos os sinais corretamente.

Ainda precisamos disso. Eu não consigo encontrar uma maneira de executar meus rollups de banco de dados após o container ter iniciado com sucesso, sem torná-lo em um monte de Makefiles.

@ victor-perov cria outro contêiner para a tarefa de roll-up e executa-o como um serviço separado

Aqui estão alguns trechos de um de nossos projetos para mostrar um serviço de tarefas para executar uma migração de banco de dados.

x-task: &task
  # run once deploy policy for tasks
  deploy:
    restart_policy: 
      condition: none
    replicas: 1

service:
  automata-auth-migrate:
    <<: *automata-auth
    <<: *task
    # without the sleep it can't lookup the host postgres.  maybe the command is ran before the network set is complete.
    command: sleep 5 && python /code/manage.py migrate --noinput

Bem, este é o quarto ano para o qual essa discussão foi estendida. Então, deixe-me adicionar meu +1 a este caso de uso de necessidade de onrun . PS: Eu deveria ter comprado pipoca para toda a discussão.

Eu também acho que onrun ou equivalente (pós-execução?) É uma obrigação. Adicionar um script de wrapper e fazer docker exec no contêiner é simplesmente ... feio.

O docker compose da IMO foi um ótimo MVP de orquestração de contêineres para convencer as pessoas de que gerenciar contêineres pode ser fácil. Talvez nós, a comunidade, devêssemos considerá-lo em "modo de manutenção", já que as soluções de orquestração prontas para produção (ou seja, kubernetes) proliferaram. Quando você tem recursos avançados, como dependências de contêiner, combinados com recursos ausentes como "executar essa coisa depois que o contêiner estiver ativo", parece que o ritmo de desenvolvimento simplesmente se estabilizou. No mínimo, não é óbvio que este recurso _deve ser_ considerado fora do escopo.

Você não pode fazer tudo facilmente com o Dockerfile. Digamos que você queira adicionar seu próprio script a um contêiner.
Por exemplo, pegue o contêiner mysql e tente adicionar um script simples para chamar uma API no caso de algum evento.
Você pode fazer isso:

  • Alterando o Dockerfile do mysql e adicione seu próprio script ao contêiner antes do ponto de entrada. Você não pode adicionar CMD em Dockerfile , uma vez que seria um argumento para ENTRYPOINT .
  • Você pode executar o contêiner e, em seguida, copiar seu script para o contêiner em execução e executá-lo [ docker cp , docker exec ].

É por isso que também acho que um recurso como onrun é benéfico, pois alterar o Dockerfile nem sempre é suficiente.

Dump, por que está fechado? Considere a situação, quando você está usando uma imagem docker oficial, como Cassandra e você precisa carregar o esquema depois de iniciado ... Tem que implementar sua própria solução de script bash para isso ... ugh, isso é feio

@somebi parece que a composição está fechada ...

Apenas meus dois centavos: eu cheguei aqui porque atualmente estou tendo que habilitar os módulos Apache manualmente toda vez que eu inicio o contêiner (SSL não é habilitado por padrão no Docker Hub wordpress image). Não é o fim do mundo, mas eu esperava executar alguns comandos sempre que subir, para que eu possa simplesmente subir e descer os contêineres sem precisar bater.

Apenas meus dois centavos: eu cheguei aqui porque atualmente estou tendo que habilitar os módulos Apache manualmente toda vez que eu inicio o contêiner (SSL não é habilitado por padrão no Docker Hub wordpress image). Não é o fim do mundo, mas eu esperava executar alguns comandos sempre que subir, para que eu possa simplesmente subir e descer os contêineres sem precisar bater.

Bem, isso pode ser facilmente resolvido se você construir uma nova imagem baseada na imagem do wordpress, que tem os módulos que você precisa habilitados. Em seguida, use-o para, por exemplo, um dockerfile:

FROM wordpress:php7.1
RUN a2enmod ssl

Outra solução seria baixar o wordpress Dockerfile e adicionar a ativação do módulo nele. Em seguida, produza uma nova imagem para si mesmo usando o docker build. Por exemplo, este é o Dockerfile para wordpress 5.2 com php 7.1:

wordpress dockerfile

você pode habilitar mais módulos na linha 63 ou executar SSL genaration.

Tudo isso não é o caso que penso que estamos discutindo aqui. O problema é a criação de ganchos dinâmicos no ciclo de vida do contêiner, como quando ele começa termina, etc.

Esta seria uma boa adição ao docker-compose!

Respostas como essas neste tópico são a razão pela qual o Kubernetes está mantendo "todo" o dinheiro que o Docker (tecnologia) está produzindo, e não é uma coisa ruim, espero que alguém compre o Docker (empresa) em breve e mude a forma como as propostas / solicitações da comunidade são bem-vindas / analisado ...

Respostas como essas neste tópico são o motivo pelo qual o Kubernetes está mantendo _ "todos" _ o mony Docker (tecnologia) está produzindo, e não é uma coisa ruim, espero que alguém compre o Docker (empresa) em breve e mude a forma como as propostas / solicitações da comunidade são bem-vindos / analisados ​​...

Eu escrevi uma crítica semelhante, sem qualquer declaração ofensiva (foi ao longo das linhas de _projetos de código aberto que não são totalmente de código aberto cujos mantenedores desafiadoramente ignoram os argumentos sem qualquer outra razão a não ser mostrar quanto argônio técnico eles possuem_), ele teve bastante apoio , e a mensagem foi removida.

Isso mostra que tipo de pessoas arrogantes estão por trás disso.

Quando sua comunidade exige algo por 4 anos e você (Docker) fecha os olhos, isso mostra que você não está olhando na mesma direção que eles: /

E agora docker desistiu e se vendeu.
Porque eles não podiam ouvir ... eles perderam.

Vergonha - mas hey ho.

É uma pena que algo assim não exista. Eu adoraria ter criado onFailure ganchos, que poderiam ocorrer quando as verificações de saúde falham.

ie

services:
  app:
    image: myapp:latest
    hooks:
      onFailure:
        - # Call a monitoring service (from the host machine) to tell it that the service is offline.

Isso seria útil nos momentos em que o aplicativo não se vincula a um soquete / porta. O Kubernetes é provavelmente o caminho a percorrer aqui, mas esta é uma mudança de infraestrutura bastante grande e um exagero para um ambiente muito pequeno.

Editar:
Para contornar isso, acabei atualizando o ponto de entrada do meu contêiner para "embrulhar" a funcionalidade de monitoramento. ie

# /app/bin/run_with_monitor
#!/bin/bash
set -eE

updateMonitoringSystem() {
 # do something here... This is run from the container, though, unfortunately.
 if [[ $? -eq 1 ]]; then
  # Failed!
 else
  # All is good!
 fi
}

trap 'updateMonitoringSystem' EXIT

$@
# Dockerfile
....
CMD ["/app/bin/run_with_monitor", "./my-app"

Ainda assim, seria bom fazer isso _sem_ ter que modificar a imagem.

: man_shrugging: Vim procurando por essa funcionalidade básica, que o concorrente (Kubernetes) tem, e em vez disso encontrei uma lixeira.

É uma pena, agora tenho que manter imagens separadas do docker para testar localmente.

Feliz ano novo: roll_eyes:

image

@LukeStonehm mesmo aqui. Necessário fazer UM comando depois que o contêiner foi levantado, mas em vez disso foi tratado com lixo quente. Eu realmente não sinto vontade de gerenciar minhas próprias imagens e arquivos do docker quando uma imagem oficial me leva a 90% ou mais do caminho.

Uma quantidade significativa de programas depende da existência de certos serviços na inicialização. Por exemplo, um banco de dados MySQL ou MongoDB.

Portanto, não há maneira sensata de usar docker-compose nesses casos.

Em vez disso, espera-se que os usuários:

  • Aprenda a escrever Dockerfiles (e programação)
  • Aprenda a construir Docker images
  • Crie Dockerfiles herdando das imagens originais, adicionando código para garantir que os contêineres esperem um pelo outro
  • Verifique regularmente se há atualizações de segurança das imagens de base
  • Modifique regularmente Dockerfiles para aplicar as atualizações
  • Crie regularmente Docker images partir desses Dockerfiles

E isso é uma merda porque:

  • Você perde muito tempo aprendendo coisas que nem precisaria de outra forma
  • Você regularmente desperdiça recursos de hardware construindo e armazenando Docker images você mesmo ou até mesmo enviando / baixando (puxando / empurrando) deles
  • Você regularmente perde tempo escrevendo aqueles Dockerfiles , construindo-os, testando-os, consertando-os etc ...
  • Você pode comprometer a segurança de suas imagens porque não sabe o que está fazendo
  • Você perde a capacidade de executar apenas Docker images oficialmente verificado / assinado

Se tivéssemos uma verificação inicial, tudo isso não seria necessário e poderíamos simplesmente mudar image: mysql:8.0.18 para image: mysql:8.0.19 quando quisermos e pronto!

Realisticamente, isso é o que está acontecendo atualmente no mundo real:

  • As pessoas criam seus próprios Dockerfiles fazendo alterações para trabalhar com docker-compose
  • Eles constroem suas imagens uma vez
  • E não os remende regularmente
  • Hackers ficam felizes

E você não pode dizer que docker-compose só deve "fazer uma coisa" porque já faz praticamente tudo. Incluindo puxar e construir imagens ainda mais importante, especificando dependências usando a propriedade depends_on . Não se trata de implementar um recurso totalmente novo, mas apenas de passar outro parâmetro para docker .

@ binman-docker @crosbymichael @dmcgowan @ebriney @ehazlett @eunomie @guillaumerose @jeanlaurent @justincormack @lorenrh @manishtomar @olegburov @routelastresort @sphhcheng @StefanScherer @thaJeztahai @ -scherer @thaJeztahai @ -scherer @thaJeztahai @ @scherer @thaJeztahai @ @scherer @thaJeztahai @
Por favor, reconsidere esse recurso ou vamos pelo menos ter uma discussão adequada sobre isso.

A técnica task service funciona muito bem para mim neste momento, mas tem suas idiossincrasias. Aplicamos o padrão em nossos arquivos de composição para migrações e inicialização de aplicativos extensivamente. mas concordo que um melhor 'Depende_on' que aguardou por uma verificação de integridade bem-sucedida ou uma saída / conclusão de tarefa bem-sucedida tornaria muitas tarefas mais fáceis e confiáveis.

Isso seria realmente uma adição útil.

Acho que vale a pena enfatizar que o Kubernetes tem essa funcionalidade por meio do ciclo de vida pós-início.

k8s! = docker-compose. Canal errado

Desculpe por não ter sido claro, mas meu ponto foi: o Kubernetes oferece suporte para isso e, como o Kubernetes e o Docker compose têm muitos dos mesmos casos de uso / finalidades, isso seria um argumento para tê-lo na composição. Desculpe se eu não estava claro.

Boas notícias!!

Acho que docker nos ouviu (sobre este assunto e alguns outros). https://www.docker.com/blog/announcing-the-compose-specification/

Vamos tentar trabalhar nas especificações para atender às necessidades da comunidade. Podemos tentar fazer desta uma comunidade aberta e amigável com este reinício.

Boas notícias!!

Acho que docker nos ouviu (sobre este assunto e alguns outros). https://www.docker.com/blog/announcing-the-compose-specification/

Vamos tentar trabalhar nas especificações para atender às necessidades da comunidade. Podemos tentar fazer desta uma comunidade aberta e amigável com este reinício.

Alguém já sugeriu essa mudança? A lista de discussão ainda não está disponível, então acho que o próximo melhor lugar é aqui: https://github.com/compose-spec/compose-spec

Não vejo um problema que descreva esse problema, mas não tenho certeza se esse é o lugar certo ...

Editar: abri um problema em https://github.com/compose-spec/compose-spec/issues/84.

Você pode usar HEALTHCHECK para fazer outra coisa, como o exemplo a seguir:

Código

Dockerfile

FROM ubuntu

COPY healthcheck.sh /healthcheck.sh
RUN chmod a+x /healthcheck.sh

HEALTHCHECK --interval=5s CMD /healthcheck.sh

CMD bash -c 'set -x; set +e; while true; do cat /test.txt; sleep 3; done'

healthcheck.sh

#/usr/bin/env bash

set -e

FIRST_READY_STATUS_FLAG='/tmp/.FIRST_READY_STATUS_FLAG'

# Health check

echo 'Run command to validate the container status HERE'

# On success
if [ ! -f "${FIRST_READY_STATUS_FLAG}" ]; then
  # On first success...
  touch "${FIRST_READY_STATUS_FLAG}"

  # Run ON_RUN on first health check ok
  if [ ! -z "${DOCKER_ON_RUN}" ]; then
    eval "${DOCKER_ON_RUN}"
  fi
fi
  1. Execute o _health check_.

    • Se falhar, sai do script com o código de saída 1 .

    • Se a _verificação de integridade_ estiver ok, o script continuará.

  2. Se for a primeira _verificação de integridade OK_ e se a variável de ambiente DOCKER_ON_RUN existir, execute-a.

Exemplo

docker-compose.yml

version: "3.7"

services:
  test:
    build:
      context: .
    image: test/on-run
    environment:
      DOCKER_ON_RUN: echo x >> /test.txt

Você pode usar a variável de ambiente DOCKER_ON_RUN para passar um comando personalizado a ser executado após a execução.

Resultado de execução

docker-compose build
docker-compose up

Resultado:

Creating network "tmp_default" with the default driver
Creating tmp_test_1 ... done
Attaching to tmp_test_1
test_1  | + set +e
test_1  | + true
test_1  | + cat /test.txt
test_1  | cat: /test.txt: No such file or directory
test_1  | + sleep 3
test_1  | + true
test_1  | + cat /test.txt
test_1  | cat: /test.txt: No such file or directory
test_1  | + sleep 3
test_1  | + true
test_1  | + cat /test.txt
test_1  | x
test_1  | + sleep 3
test_1  | + true
test_1  | + cat /test.txt
test_1  | x
test_1  | + sleep 3
test_1  | + true
test_1  | + cat /test.txt
test_1  | x
test_1  | + sleep 3
  • Você pode ver o erro cat: /test.txt: No such file or directory até que a _verificação de saúde_ esteja pronta.
  • Você pode ver apenas um x dentro de /test.txt após a execução .

Espero que isso possa ajudar alguém.

Editar 1

Se você não precisa de uma _verificação de saúde_, pode usar o restante do script.

@ reduardo7
Obrigado pela sua solução alternativa.
Só quero adicionar, no caso de precisar executar o comando um, como para criação de usuários ou etc, você pode montar o volume para touch "${FIRST_READY_STATUS_FLAG}"

Muitas dessas soluções são soluções alternativas válidas para esse problema. Por exemplo, fazer um script de ponto de entrada também pode resolver isso:
ENTRYPOINT ["./entrypoint.sh"]

que incluirá uma lógica mais complexa antes de executar o serviço ou processo real.
Isso ainda não é um gancho que nos permitiria injetar lógica no ciclo de vida do contêiner:

  • antes de criar
  • Antes de começar
  • depois de começar
  • antes de destruir
  • mesmo depois de destruir
  • etc ...

Eu sei que nem todos os itens acima são significativos, mas espero que você entenda, porque este é o ponto.
Isso também pode ser incluído em docker-compose com uma diretiva como:

lifecycle:
    before_start: "./beforeStartHook.sh"
    after_destroy: "./afterDestroyHook.sh"

ou mesmo assim:

hooks:
    before_destroy: "./beforeDestroyHook.sh"
    before_create: "./fixFsRights.sh"

Não consigo substituir o arquivo que requer permissão de root usando a abordagem de script de gancho ou script de bootstrap, uma vez que iniciamos o contêiner como um usuário não root

Nossa, uma funcionalidade tão básica e ainda não implementada.

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