Другое событие NullPointerException
возникает, когда объявляется массив объектов, а затем сразу же пытается разыменовать его внутри.
String[] phrases = new String[10];
String keyPhrase = "Bird";
for(String phrase : phrases) {
System.out.println(phrase.equals(keyPhrase));
}
Этот конкретный NPE можно избежать, если порядок сравнения отменяется ; а именно, использовать .equals
для гарантированного непустого объекта.
Все элементы внутри массива инициализируются их общим начальным значением ; для любого типа массива объектов, это означает, что все элементы null
.
Вы должны инициализировать элементы в массиве перед доступом или разыменованием их.
String[] phrases = new String[] {"The bird", "A bird", "My bird", "Bird"};
String keyPhrase = "Bird";
for(String phrase : phrases) {
System.out.println(phrase.equals(keyPhrase));
}
RUN /bin/bash -c "source /usr/local/bin/virtualenvwrapper.sh"
Проверьте команду SHELL . По умолчанию оболочка на Linux - это ["/ bin / sh", "-c"]
RUN "source file" # translates to: RUN /bin/sh -c "source file"
Вы можете изменить оболочку по умолчанию, используя SHELL
, которая меняет оболочку, используемую для последующих команд RUN
в Dockerfile
SHELL ["/bin/bash", "-c"]
Теперь оболочка по умолчанию изменилась, и вам не нужно явно определять ее в каждой инструкции RUN
RUN "source file" # now translates to: RUN /bin/bash -c "source file"
. Дополнительная заметка: вы также можете добавить --login
который запускает оболочку входа. Это означает, что ~/.bachrc
, например, будет прочитан, и вам не нужно явно указывать его перед вашей командой
У меня была та же проблема, и для выполнения установки pip внутри virtualenv мне пришлось использовать эту команду:
RUN pip install virtualenv virtualenvwrapper
RUN mkdir -p /opt/virtualenvs
ENV WORKON_HOME /opt/virtualenvs
RUN /bin/bash -c "source /usr/local/bin/virtualenvwrapper.sh \
&& mkvirtualenv myapp \
&& workon myapp \
&& pip install -r /mycode/myapp/requirements.txt"
Надеюсь, это поможет.
Согласно https://docs.docker.com/engine/reference/builder/#run по умолчанию [Linux] для RUN
является /bin/sh -c
. Кажется, вы ожидаете багизмов, поэтому вы должны использовать «форму exec» для RUN
, чтобы указать вашу оболочку.
RUN ["/bin/bash", "-c", "source /usr/local/bin/virtualenvwrapper.sh"]
В противном случае, используя «оболочечную форму» RUN и указав другую оболочку приводит к вложенным оболочкам.
# don't do this...
RUN /bin/bash -c "source /usr/local/bin/virtualenvwrapper.sh"
# because it is the same as this...
RUN ["/bin/sh", "-c", "/bin/bash" "-c" "source /usr/local/bin/virtualenvwrapper.sh"]
Если у вас более 1 команды, которым требуется другая оболочка, вы должны прочитать https://docs.docker.com/engine/reference/builder/ #shell и измените оболочку по умолчанию, поставив ее перед вашими командами RUN:
SHELL ["/bin/bash", "-c"]
Наконец, если вы поместили что-либо в файл .bashrc
пользователя root, который вам нужен, вы можете добавьте флаг -l
в команду SHELL
или RUN
, чтобы сделать его оболочкой входа и убедитесь, что она получена.
Примечание. Я намеренно игнорировал тот факт, что это бессмысленно для источника сценарий как единственная команда в RUN.
sh
до bash
– Bhargav Nanekalva
19 October 2015 в 15:15
ln -s /bin/bash /bin/sh
Это ужасная идея. ubuntu цели / bin / sh для тире по какой-либо причине. тире - это полностью posix-оболочка, которая на порядки выше, чем bash. привязка / bin / sh к bash резко снизит производительность вашего сервера. cite: wiki.ubuntu.com/DashAsBinSh
– xero
9 May 2016 в 18:35
sh
, но вы хотите bash
, правильным решением является либо процесс sh
вызывать bash
как одноразовый, например. bash -c 'source /script.sh && …'
, или i>, вы можете даже дойти до того, что полностью избегаете бахизмов (например, source
) и вместо этого предпочитаете использовать только действительные эквиваленты POSIX, например. . /script.sh
. (Запомните пробел после .
!) Наконец, если ваш скрипт является исполняемым (не просто исходным), never i> заставляет ваш скрипт лежать в #!/bin/sh
shebang, если он не является sh-совместимым. Вместо этого используйте #!/bin/bash
.
– Mark G.
13 September 2016 в 13:56
SHELL ["/bin/sh", "-c", "-l"]
, поэтому он источник ~ / .bashrc и т. д., если у вас есть настройки среды из базового контейнера
– MortenB
17 August 2018 в 17:38
/bin/sh
, который не решит проблему bash, которая не используется. Кроме того, когда вы делаете docker build
, маловероятно, что вам понадобится что-то полезное в .bashrc пользователя root. Но, если вы помещаете что-то там раньше в Dockerfile (например, возможно, JAVA_HOME
, то да. В своем ответе я напишу об этом.
– Bruno Bronosky
17 August 2018 в 17:51
Я закончил тем, что поместил свой материал env в .profile
и мутировал SHELL
что-то вроде
SHELL ["/bin/bash", "-c", "-l"]
# Install ruby version specified in .ruby-version
RUN rvm install $(<.ruby-version)
# Install deps
RUN rvm use $(<.ruby-version) && gem install bundler && bundle install
CMD rvm use $(<.ruby-version) && ./myscript.rb
Если вы используете Docker 1.12 или новее, просто используйте SHELL
!
general:
SHELL ["/bin/bash", "-c"]
для python vituralenv :
SHELL ["/bin/bash", "-c", "source /usr/local/bin/virtualenvwrapper.sh"]
из https://docs.docker.com/engine/reference/builder/#/shell
SHELL ["executable", "parameters"]
Команда SHELL позволяет использовать оболочку по умолчанию, используемую для оболочки команд команд для переопределения. Стандартная оболочка в Linux - это ["/ bin / sh", "-c"], а в Windows - ["cmd", "/ S", "/ C"]. Инструкция SHELL должна быть записана в форме JSON в файле Docker.
Инструкция SHELL особенно полезна в Windows, где есть две обычно используемые и совершенно разные родные оболочки: cmd и powershell, а также альтернативные оболочки включая sh.
Инструкция SHELL может появляться несколько раз. Каждая команда SHELL отменяет все предыдущие инструкции SHELL и влияет на все последующие инструкции. Например:
FROM microsoft/windowsservercore # Executed as cmd /S /C echo default RUN echo default # Executed as cmd /S /C powershell -command Write-Host default RUN powershell -command Write-Host default # Executed as powershell -command Write-Host hello SHELL ["powershell", "-command"] RUN Write-Host hello # Executed as cmd /S /C echo hello SHELL ["cmd", "/S"", "/C"] RUN echo hello
Следующие инструкции могут быть затронуты инструкцией SHELL, когда форма оболочки из них используется в файле Docker: RUN, CMD и ENTRYPOINT.
Следующие пример - общий шаблон, найденный в Windows, который можно оптимизировать с помощью инструкции SHELL:
... RUN powershell -command Execute-MyCmdlet -param1 "c:\foo.txt" ...
Команда, вызываемая докером, будет:
cmd /S /C powershell -command Execute-MyCmdlet -param1 "c:\foo.txt"
Это неэффективно для две причины. Во-первых, вызывается ненужный командный процессор cmd.exe (aka shell). Во-вторых, для каждой инструкции RUN в форме оболочки требуется дополнительная команда powershell-command, префиксная команда.
Чтобы сделать это более эффективным, можно использовать один из двух механизмов. Один из них - использовать форму JSON команды RUN, такую как:
... RUN ["powershell", "-command", "Execute-MyCmdlet", "-param1 \"c:\\foo.txt\""] ...
. Хотя форма JSON недвусмысленная и не использует ненужный cmd.exe, для этого требуется более многословие, цитируя и убегая. Альтернативным механизмом является использование команды SHELL и формы оболочки, что делает более естественным синтаксис для пользователей Windows, особенно в сочетании с директивой анализа парсера:
# escape=` FROM microsoft/nanoserver SHELL ["powershell","-command"] RUN New-Item -ItemType Directory C:\Example ADD Execute-MyCmdlet.ps1 c:\example\ RUN c:\example\Execute-MyCmdlet -sample 'hello world'
Результат:
PS E:\docker\build\shell> docker build -t shell . Sending build context to Docker daemon 4.096 kB Step 1/5 : FROM microsoft/nanoserver ---> 22738ff49c6d Step 2/5 : SHELL powershell -command ---> Running in 6fcdb6855ae2 ---> 6331462d4300 Removing intermediate container 6fcdb6855ae2 Step 3/5 : RUN New-Item -ItemType Directory C:\Example ---> Running in d0eef8386e97 Directory: C:\ Mode LastWriteTime Length Name ---- ------------- ------ ---- d----- 10/28/2016 11:26 AM Example ---> 3f2fbf1395d9 Removing intermediate container d0eef8386e97 Step 4/5 : ADD Execute-MyCmdlet.ps1 c:\example\ ---> a955b2621c31 Removing intermediate container b825593d39fc Step 5/5 : RUN c:\example\Execute-MyCmdlet 'hello world' ---> Running in be6d8e63fe75 hello world ---> 8e559e9bf424 Removing intermediate container be6d8e63fe75 Successfully built 8e559e9bf424 PS E:\docker\build\shell>
Инструкция SHELL также может использоваться для изменения способа работы оболочки. Например, используя SHELL cmd / S / C / V: ON | OFF в Windows, можно было бы модифицировать семантику расширения замедленной среды.
Инструкция SHELL может также использоваться в Linux, если требуется чередование оболочки такие как zsh, csh, tcsh и другие.
Функция SHELL была добавлена в Docker 1.12.
Самый простой способ - использовать оператор точки вместо источника, что эквивалентно команде bash source
:
Вместо:
RUN source /usr/local/bin/virtualenvwrapper.sh
Использовать :
RUN . /usr/local/bin/virtualenvwrapper.sh
.
/ source
также принимает позиционные параметры после имени файла
– Wes Turner
27 July 2016 в 16:31
source
или .
теряются при завершении команды RUN. См. stackoverflow.com/a/40045930/19501
– amit_grepclub
29 June 2018 в 02:07
Это может произойти, потому что source
является встроенным в bash, а не двоичным где-то в файловой системе. Является ли ваше намерение использовать сценарий, который вы используете для изменения контейнера после этого?
Если вы просто пытаетесь использовать pip для установки чего-то в virtualenv, вы можете изменить PATH env, чтобы сначала просмотреть папку bin в виртуальном каталоге
ENV PATH="/path/to/venv/bin:${PATH}"
Затем любые команды pip install
, которые следуют в файле Docker, сначала найдут / path / to / venv / bin / pip и будут использовать это, которое будет установлено в этот virtualenv, а не системный python.
Основываясь на ответах на этой странице, я бы добавил, что вы должны знать, что каждый оператор RUN работает независимо от других с помощью /bin/sh -c
и, следовательно, не будет получать каких-либо окружающих vars, которые, как правило, будут получены в оболочках входа.
Лучший способ, который я нашел до сих пор, - добавить скрипт в /etc/bash.bashrc
, а затем вызвать каждую команду в качестве входа в bash.
RUN echo "source /usr/local/bin/virtualenvwrapper.sh" >> /etc/bash.bashrc
RUN /bin/bash --login -c "your command"
Вы могли бы, например, установить и настроить virtualenvwrapper, создать виртуальный env, активировать его при использовании входа в bash, а затем установить ваши модули python в это env:
RUN pip install virtualenv virtualenvwrapper
RUN mkdir -p /opt/virtualenvs
ENV WORKON_HOME /opt/virtualenvs
RUN echo "source /usr/local/bin/virtualenvwrapper.sh" >> /etc/bash.bashrc
RUN /bin/bash --login -c "mkvirtualenv myapp"
RUN echo "workon mpyapp" >> /etc/bash.bashrc
RUN /bin/bash --login -c "pip install ..."
Чтение руководства в файлах загрузки bash помогает понять, что получается, когда.
ADD env-file /etc/profile.d/installerenv.sh
RUN /bin/bash --login -c 'env'
RUN /bin/bash -c 'rm /etc/profile.d/installerenv.sh'
Если в случае использования добавляется больше переменных среды инъекции в перспективу построения докеров, как и у меня, я бы рекомендовал взглянуть на docs.docker.com/compose/yml/#env-file тоже.
– daniel.kahlenberg
28 July 2015 в 10:26
RUN
, а это значит, что вы не можете установить множество зависимостей проекта, а затем скопировать исходный код и воспользоваться преимуществами преимущества промежуточного кэширования Docker. Он будет переустанавливать все зависимости проекта каждый раз.
– erewok
15 June 2016 в 21:57
/etc/bashrc
для Redhat вместо /etc/bash.bashrc
, как указано выше (для Ubuntu)
– Jordan Gee
15 November 2017 в 06:49
У меня также были проблемы с запуском source
в файле Dockerfile
. Это отлично работает для создания контейнера Docker CentOS 6.6, но давало проблемы в контейнерах Debian
RUN cd ansible && source ./hacking/env-setup
. как я это решал, может быть, не изящный способ, но это то, что сработало для меня
RUN echo "source /ansible/hacking/env-setup" >> /tmp/setup
RUN /bin/bash -C "/tmp/setup"
RUN rm -f /tmp/setup
Возможно, вы захотите запустить bash -v
, чтобы посмотреть, что происходит.
Я бы сделал следующее вместо игры с символическими ссылками:
RUN echo "source /usr/local/bin/virtualenvwrapper.sh" >> /etc/bash.bashrc
source
вообще, а толькоbash /usr/local/bin/virtualenvwrapper.sh
, в таком случае? – Charles Duffy 21 June 2016 в 13:31RUN /bin/bash -c "source /usr/local/bin/virtualenvwrapper.sh; my_command; my_command; my_command;"
– Leons 1 September 2016 в 02:28/bin/sh -c
является оболочкой по умолчанию, эта «форма оболочки» означает, RUN переводится наRUN ["/bin/sh", "-c", "/bin/bash" "-c" "source /usr/local/bin/virtualenvwrapper.sh"]
. Вы должны продолжить и использовать форму "exec" из RUN, чтобы вы могли вывестиsh
так, какRUN ["/bin/bash" "-c" "source /usr/local/bin/virtualenvwrapper.sh"]
– Bruno Bronosky 13 July 2017 в 16:50bash
, вложенный вsh
, и поэтому его следует избегать. – Bruno Bronosky 13 July 2017 в 17:10