2016-06-15 5 views
7

У меня есть изображение Docker, которое использует сценарий (/bin/bash /init.sh) в качестве точки входа. Я хотел бы выполнить этот скрипт только при первом запуске контейнера. Он должен быть опущен, когда контейнеры перезапускаются или запускаются снова после сбоя демона докеров.Запустить команду в контейнере Docker только при первом запуске

Есть ли способ сделать это с самим докером или сделать, если нужно выполнить какую-то проверку в скрипте?

ответ

9

Точка входа для контейнера докера сообщает демону docker, что нужно запускать, когда вы хотите «запустить» этот конкретный контейнер. Давайте зададим вопросы «что контейнер должен запускать, когда он запускается второй раз?» или «что контейнер должен запускать после перезагрузки?»

Возможно, что вы делаете, придерживается того же подхода, который вы применяете с механизмами инициализации «старой школы». Ваш скрипт «устанавливает» необходимые сценарии, и вы запустите свое приложение в качестве службы systemd/upstart, не так ли? Если вы это делаете, вы должны изменить это на более «докционированное» определение.

Точка входа для этого контейнера должна быть сценарием, который фактически запускает ваше приложение, а не настраивает его. Предположим, что вам нужно установить java для запуска вашего приложения. Таким образом, в dockerfile вы создали базовый контейнер для установки все, что вам нужно, как:

FROM alpine:edge 

RUN apk --update upgrade && apk add openjdk8-jre-base 
RUN mkdir -p /opt/your_app/ && adduser -HD userapp 

ADD target/your_app.jar /opt/your_app/your-app.jar 
ADD scripts/init.sh /opt/your_app/init.sh 

USER userapp 
EXPOSE 8081 

CMD ["/bin/bash", "/opt/your_app/init.sh"] 

Наших контейнеров, в компании я работаю, перед запуском фактического приложения в init.sh сценарии они Позовите configs from consul (вместо предоставления точки монтирования и размещения конфигураций внутри хоста или встроенных в контейнер). Таким образом, скрипт будет выглядеть примерно так:

#!/bin/bash 

echo "Downloading config from consul..." 
confd -onetime -backend consul -node $CONSUL_URL -prefix /cfgs/$CONSUL_APP/$CONSUL_ENV_NAME 
echo "Launching your-app..." 
java -jar /opt/your_app/your-app.jar 

Один совет, который я могу дать вам (в моем очень коротком опыте работы с контейнерами) обращаться со своими контейнерами, как если бы они были лицами без гражданства, как только они предоставлены (все команды, которые выполняются перед точкой входа).

+1

Полностью согласен с рассмотрением контейнеров без гражданства. Если есть данные для инициализации, поместите их в том. – BMitch

+2

Я бы очень хотел следовать вашему совету, но все не так просто. Я очень мало влияю на изменения приложения, и его нужно было изменить LOT, чтобы использовать его так, как вы описали. Например: при каждом запуске контейнера сценарий инициализации создает базу данных для приложения. Это не должно происходить, когда контейнер перезагружается, потому что он перезаписывает данные, которые уже существуют ... К сожалению, это очень сложно научить разработчиков приложения использовать докер. Поэтому я стараюсь, чтобы это было очень просто для них. – christian

+0

как вы это используете? – StarWind0

1

Я хотел сделать то же самое на контейнере с окнами. Это может быть достигнуто с помощью планировщика задач на окнах. Эквивалент Linux для задачи Scheduler - cron. Вы можете использовать это в своем случае. Для того, чтобы сделать это изменение в dockerfile и добавьте следующую строку в конце

WORKDIR /app 
COPY myTask.ps1 . 
RUN schtasks /Create /TN myTask /SC ONSTART /TR "c:\WINDOWS\system32\WindowsPowerShell\v1.0\powershell.exe C:\app\myTask.ps1" /ru SYSTEM 

Это создает задачу с именем myTask запускает его OnStart и задача его самость выполнить Powershell скрипт помещен в «C: \ приложение \ myTask.ps1" .

Этот скрипт myTask.ps1 будет выполнять любую инициализацию, необходимую для запуска контейнера. Удостоверьтесь, что вы удаляете эту задачу после ее успешного выполнения или запускаете ее при каждом запуске. Чтобы удалить его, вы можете использовать следующую команду в конце скрипта myTask.ps1.

schtasks /Delete /TN myTask /F 
0

Я должен был сделать это, и я в конечном итоге делаю docker run -d, который только что создал отстраненный контейнер и начал bash (в фоновом режиме), за которым следует docker exec, что сделали необходимую инициализацию. вот пример

docker run -itd --name=myContainer myImage /bin/bash 
docker exec -it myContainer /bin/bash -c /init.sh 

Теперь, когда я перезагрузить мой контейнер, я могу просто сделать

docker start myContainer 
docker attach myContainer 

Это не может быть идеальным, но отлично работает для меня.

Смежные вопросы