containers – Dockerfile unable to execute CMD command (docker for windows) – Stack Overflow

Введение

Существует много статей про запуск контейнеров и написание

docker-compose.yml

. Но для меня долгое время оставался не ясным вопрос, как правильно поступить, если какой-то контейнер не должен запускаться до тех пор, пока другой контейнер не будет готов обрабатывать его запросы или не выполнит какой-то объём работ.

Вопрос этот стал актуальным, после того, как мы стали активно использовать docker-compose, вместо запуска отдельных докеров.

Cmd: duplicates are allowed but wasteful

GingerBeer makes an important point: you won’t get any errors if you put in more than one CMD – but it’s wasteful to do so. I’d like to elaborate with an example:

Docker windows containers cmd – command not running

I have a docker image that ends with the following CMD:

CMD ["powershell", "c:installsettingsinstall.ps1"]

or

CMD powershell c:installsettingsinstall.ps1

It did not execute (or perhaps the volume is not mounted yet).

Settings are placed in a mounted volume, and it is started with:

docker run -d -p 80:80 --name openid --rm -v D:settings:c:installsettings mydocker

If I run the command after starting the docker image:

docker exec openid powershell c:installsettingsinstall.ps1

It runs fine.

Is there a way of doing this?

Or is there a better way of deploying an IIS website with webdeploy and custom SetParameters.xml?

Dockerfile unable to execute cmd command (docker for windows)

I think you may be misunderstanding the nature of the CMD versus ENTRYPOINT vs RUN instruction. Both CMD and ENTRYPOINT take effect at container startup/runtime, whereas RUN is a build-time command. Somewhat confusingly, you use RUN to prepare your container image during the docker build process, while the CMD is what gets run in the container.

via the documentation,

The main purpose of a CMD is to provide defaults for an executing container…

Any given container image will only ever have a single CMD instruction.

There can only be one CMD instruction in a Dockerfile. If you list more than one CMD then only the last CMD will take effect.

If you want to make sure that an executable runs at container start, then you might consider using the ENTRYPOINT instruction; think of ENTRYPOINT as being a command that supplies defaults to the CMD instruction. From the docs:

Dockerfile should specify at least one of CMD or ENTRYPOINT commands.
ENTRYPOINT should be defined when using the container as an executable.
CMD should be used as a way of defining default arguments for an ENTRYPOINT command or for executing an ad-hoc command in a container.
CMD will be overridden when running the container with alternative arguments.

The RUN command is a build-time instruction that you use to prepare your container image with necessary files, configuration, etc.

See this SO question for more on ENTRYPOINT vs CMD.

ED: The case you’re looking at, running a SQL script in the container, is a tricky one because the script must not run before the database engine is ready to accept commands. You could run the upgrade script in the ENTRYPOINT instruction as a first step. You may also consider running the SQL upgrade script post-container provisioning, via a docker exec command.

:/>  Список бесплатных видеоредакторов для Windows 10

ED2: The example provided:

ENTRYPOINT ["powershell", "-NoProfile", "-Command", "sqlcmd"] CMD ["sqlcmd -S database -i C:dbdb_scriptsupgradescript.sql -U sa -P mypassword"]

does not work because it results in what is probably a nonsense command-line instruction. Remember that the CMD supplies parameters to the ENTRYPOINT instruction, so you’ll only specify the powershell sqlcmd in the ENTRYPOINT, leaving CMD to supply the parameters (this is untested, OTOMH):

ENTRYPOINT powershell sqlcmd -S database -U sa -P mypassword -i

CMD C:dbdb_scriptsupgradescript.sql

ED 3:
By combining the two statements and adding a statement terminator (;) to the ENTRYPOINT, you could then allow the standard SQL container .Start.ps1 script to run, which enters an infinite loop that prevents the container from stopping immediately (containers run only as long as the executed process in them is running). This guarantees that your startup script is executed, even if the user overrides the CMD instruction at runtime:

ENTRYPOINT powershell "sqlcmd -S database -U sa -P mypassword -i 'C:dbdb_scriptsupgradescript.sql';"

CMD .Start.ps1

Pull (выгрузка из реестра) образа

docker pull nginx

Push (загрузка в реестр) образа

docker push eon01/nginx

Run: commands may not execute if images are cached

A subtle point to notice about RUN is that it’s treated as a pure function even if there are side-effects, and is thus cached. What this means is that if RUN had some side effects that don’t change the resultant image, and that image has already been cached, the RUN won’t be executed again and so the side effects won’t happen on subsequent builds. For example, take this Dockerfile:

Windows

Используйте MSI-инсталлятор:

Блокировка (до остановки контейнера)

docker wait nginx

Вход в реестр

docker login
docker login localhost:8080

Выполняющиеся процессы

docker top infinite

Выход из реестра

docker logout
docker logout localhost:8080

Для чего это надо


Действительно, пусть приложение в контейнере B зависит от готовности сервиса в контейнере A. И вот при запуске, приложение в контейнере B этот сервис не получает. Что оно должно делать?

Варианта два:

  • первый — умереть (желательно с кодом ошибки)
  • второй — подождать, а потом всё равно умереть, если за отведённый тайм-аут приложение в контейнере B так и не ответило

После того как контейнер B умер,

docker-compose

(в зависимости от настройки конечно) перезапустит его и приложение в контейнере B снова попытается достучаться до сервиса в контейнере A.

Так будет продолжаться, пока сервис в контейнере A не будет готов отвечать на запросы, либо пока мы не заметим, что у нас постоянно перегружается контейнер.И по сути, это нормальный путь для многоконтейнерной архитектуры.

Но, мы, в частности, столкнулись с ситуацией, когда контейнер А запускается и готовит данные для контейнера B. Приложение в контейнере B не умеет само проверять готовы данные или нет, оно сразу начинает с ними работать. Поэтому, сигнал о готовности данных нам приходится получать и обрабатывать самостоятельно.

Думаю, что можно ещё привести несколько вариантов использования. Но главное, надо точно понимать зачем вы этим занимаетесь. В противном случае, лучше пользоваться стандартными средствами docker-compose

:/>  Как отключить автозапуск программ при включении компьютера Windows 10, 7

Загрузка репозитория в tar (из файла или стандартного ввода)

docker load < ubuntu.tar.gz
docker load --input ubuntu.tar

Запуск остановленного контейнера

docker start nginx

Изменения в файлах или директориях файловой системы контейнера

docker diff infinite

Инициализация swarm

docker swarm init --advertise-addr 192.168.10.1

Информация о контейнере

docker inspect infinite

Использование wait-for-it.sh


Сразу стоит сказать, что этот путь у нас не заработал так, как это описано в документации.

А именно, известно, что если в Dockerfile прописать

ENTRYPOINTCMD

, то при запуске контейнера будет выполняться команда из

ENTRYPOINT

, а в качестве параметров ей будет передано содержимое

CMD

Также известно, что ENTRYPOINT и CMD, указанные в Dockerfile, можно переопределить в docker-compose.yml

Формат запуска wait-for-it.sh следующий:

wait-for-it.sh адрес_и_порт -- команда_запускаемая_после_проверки

Тогда, как указано в

, мы можем определить новую

ENTRYPOINTdocker-compose.yml

, а

CMD

подставится из

Dockerfile

Итак, получаем:

Докер файл для контейнера А остаётся без изменений:

Использование ресурсов

docker stats infinite

Как это реализуется

Для решения этой задачи мне сильно помогло описание

docker-compose

, вот

её часть

, рассказывающая про правильное использование

entrypointcmd

Итак, что нам нужно получить:

  • есть приложение А, которое мы завернули в контейнер А
  • оно запускается и начинает отвечать OK по порту 8000
  • а также, есть приложение B, которое мы стартуем из контейнера B, но оно должно начать работать не ранее, чем приложение А начнёт отвечать на запросы по 8000 порту

Официальная документация предлагает два пути для решения этой задачи.

Первый это написание собственной entrypoint в контейнере, которая выполнит все проверки, а потом запустит рабочее приложение.

Второй это использование уже написанного командного файла wait-for-it.sh.Мы попробовали оба пути.

Логи контейнера

docker logs infinite

Масштабирование сервиса

docker service scale vote=3

Написание собственной entrypoint


Что такое

entrypoint

Это просто исполняемый файл, который вы указываете при создании контейнера в Dockerfile в поле ENTRYPOINT. Этот файл, как уже было сказано, выполняет проверки, а потом запускает основное приложение контейнера.

Итак, что у нас получается:

Создадим папку Entrypoint.

В ней две подпапки — container_A и container_B. В них будем создавать наши контейнеры.

Немного идеологии

Если внимательно читать документацию, то там всё написано. А именно — каждый

контейнер единица самостоятельная и должен сам позаботиться о том, что все сервисы, с

которыми он собирается работать, ему доступны.

Поэтому, вопрос состоит не в том запускать или не запускать контейнер, а в том, чтобывнутри контейнера выполнить проверку на готовность всех требуемых сервисов и толькопосле этого передать управление приложению контейнера.

Обновление контейнера

docker update --cpu-shares 512 -m 300M infinite

Обновление сервиса

docker service update --image instavote/vote:movies vote
docker service update --force --update-parallelism 1 --update-delay 30s nginx
docker service update --update-parallelism 5--update-delay 2s --image instavote/vote:indent vote
docker service update --limit-cpu 2 nginx
docker service update --replicas=5 nginx

Остановка

docker stop nginx

Остановка и удаление всех контейнеров

docker stop $(docker ps -a -q) && docker rm $(docker ps -a -q)

Отключение контейнера от сети

docker network disconnect MyOverlayNetwork nginx

Отправка sigkill (завершающего сигнала)

docker kill nginx

Отправка другого сигнала

docker kill -s HUP nginx

Пауза (приостановка всех процессов контейнера)

docker pause nginx

Первый запуск контейнера

docker run -it --name infinite -d eon01/infinite

Перезагрузка

docker restart nginx

Переименование контейнера

docker rename infinite infinity

Подключение к существующему контейнеру

docker attach nginx

Подключение контейнера к сети при его запуске

docker run -it -d --network=MyOverlayNetwork nginx

Подключение работающего контейнера к сети

docker network connect MyOverlayNetwork nginx

Подключение рабочего узла (worker) к swarm

docker swarm join-token worker

Подключение управляющего узла (manager) к swarm

docker swarm join-token manager

Поиск образа

docker search nginx
docker search nginx -- filter stars=3 --no-trunc busybox

Получение информации о сети

docker network inspect MyOverlayNetwork

Просмотр истории образа

docker history

Публичные порты

docker port infinite

Работающие контейнеры

docker ps
docker ps -a

Работающий вариант

Тогда, остаётся только один вариант. То, что у нас указано в

:/>  Не отображаются эскизы (миниатюры) изображений Windows 10 | remontka.pro

CMDDockerfile

, мы должны перенести в

commanddocker-compose.yml

Тогда, Dockerfile контейнера B оставим без изменений, а docker-compose.yml будет выглядеть так:

Снятие паузы

docker unpause nginx

События контейнера

docker events infinite

Создание контейнера

docker create -t -i eon01/infinite --name infinite

Создание образа из контейнера

docker commit nginx

Создание образов

docker build .

Создание сервиса

docker service create --name vote -p 8080:80 instavote/vote

Создание сети

docker network create -d overlay MyOverlayNetwork
docker network create -d bridge MyBridgeNetwork
docker network create -d overlay 
  --subnet=192.168.0.0/16 
  --subnet=192.170.0.0/16 
  --gateway=192.168.0.100 
  --gateway=192.170.0.100 
  --ip-range=192.168.1.0/24 
  --aux-address="my-router=192.168.1.5" --aux-address="my-switch=192.168.1.6" 
  --aux-address="my-printer=192.170.1.5" --aux-address="my-nas=192.170.1.6" 
  MyOverlayNetwork

Сохранение образа в tar-архив

docker save busybox > ubuntu.tar

Список заданий swarm

docker service ps

Список образов

docker images

Список сервисов

docker service ls

Список сетей

docker network ls

Список узлов

docker node ls

Тегирование образа

docker tag nginx eon01/nginx

Удаление всех контейнеров со статусом exited

docker rm $(docker ps -a -f status=exited -q)

Удаление всех неиспользуемых объектов

docker system prune

По умолчанию для Docker 17.06.1 тома не удаляются. Чтобы удалились и они тоже:

docker system prune --volumes

Удаление всех образов

docker rmi $(docker images -a -q)

Удаление всех образов без тегов

docker rmi -f $(docker images | grep "^<none>" | awk "{print $3}")

Удаление всех остановленных контейнеров

docker container prune
docker rm `docker ps -a -q`

Удаление контейнера

docker rm infinite

Удаление контейнера и его тома (volume)

docker rm -v nginx

Удаление контейнеров, остановленных более суток назад

docker container prune --filter "until=24h"

Удаление неиспользуемых (dangling) образов

docker image prune
docker rmi $(docker images -f dangling=true -q)

Удаление неиспользуемых (dangling) образов даже с тегами

docker image prune -a

Удаление неиспользуемых (dangling) томов

docker volume prune
docker volume rm $(docker volume ls -f dangling=true -q)

Удаление неиспользуемых (dangling) томов по фильтру

docker volume prune --filter "label!=keep"

Удаление неиспользуемых сетей

docker network prune

Удаление образа

docker rmi nginx

Удаление работающего контейнера

docker rm nginx

Удаление сети

docker network rm MyOverlayNetwork

Оставьте комментарий

Adblock
detector