无法使用 sdkman 构建 dockerfile
Cannot build dockerfile with sdkman
我对 docker 的概念完全陌生。我正在创建以下 Dockerfile 作为练习。
FROM ubuntu:latest
MAINTAINER kesarling
RUN apt update && apt upgrade -y
RUN apt install nginx curl zip unzip -y
RUN apt install openjdk-14-jdk python3 python3-doc clang golang-go gcc g++ -y
RUN curl -s "https://get.sdkman.io" | bash
RUN bash /root/.sdkman/bin/sdkman-init.sh
RUN sdk version
RUN yes | bash -c 'sdk install kotlin'
CMD [ "echo","The development environment has now been fully setup with C, C++, JAVA, Python3, Go and Kotlin" ]
我正在使用 SDKMAN! to install Kotlin
. The problem initially was that instead of using RUN bash /root/.sdkman/bin/sdkman-init.sh
, I was using RUN source /root/.sdkman/bin/sdkman-init.sh
. However, it gave the error saying source
not found. So, I tried using RUN . /root/.sdkman/bin/sdkman-init.sh
, and it did not work. However, RUN bash /root/.sdkman/bin/sdkman-init.sh
seems 工作,因为没有给出任何错误并尝试 运行 下一个命令。然而, docker 然后给出错误说 sdk: not found
我哪里错了?
应该注意的是,这些步骤对我的主机发行版(我 运行 宁 docker 的发行版)非常有效,即 Pop!_OS 20.04
实际上脚本 /root/.sdkman/bin/sdkman-init.sh
来源 sdk
source 是 bash 的内置文件,而不是文件系统某处的二进制文件。
source命令执行当前shell中的文件。
每个 运行 指令将在当前图像之上的新层中执行任何命令并提交结果。
生成的提交映像将用于 Dockerfile 中的下一步。
试试这个:
FROM ubuntu:latest
MAINTAINER kesarling
RUN apt update && apt upgrade -y
RUN apt install nginx curl zip unzip -y
RUN apt install openjdk-14-jdk python3 python3-doc clang golang-go gcc g++ -y
RUN curl -s "https://get.sdkman.io" | bash
RUN /bin/bash -c "source /root/.sdkman/bin/sdkman-init.sh; sdk version; sdk install kotlin"
CMD [ "echo","The development environment has now been fully setup with C, C++, JAVA, Python3, Go and Kotlin" ]
通常您想避免在 Docker 中使用 "version manager" 类型的工具;最好安装您需要的特定版本的编译器或运行时。
就 Kotlin 而言,它是一个 JVM 应用程序 distributed as a zip file 因此安装应该相当容易:
FROM openjdk:15-slim
ARG KOTLIN_VERSION=1.3.72
# Get OS-level updates:
RUN apt-get update \
&& apt-get install --no-install-recommends --assume-yes \
curl \
unzip
# and if you need C/Python dependencies, those too
# Download and unpack Kotlin
RUN cd /opt \
&& curl -LO https://github.com/JetBrains/kotlin/releases/download/v${KOTLIN_VERSION}/kotlin-compiler-${KOTLIN_VERSION}.zip \
&& unzip kotlin-compiler-${KOTLIN_VERSION}.zip \
&& rm kotlin-compiler-${KOTLIN_VERSION}.zip
# Add its directory to $PATH
ENV PATH=/opt/kotlinc/bin:$PATH
版本管理器的真正问题在于它们严重依赖于工具设置环境变量。正如@JeevanRao 在 中指出的那样,每个 Dockerfile RUN
命令在单独的容器中的单独 shell 中运行,并且该命令中的任何环境变量设置都会丢失下一个命令。
# Does absolutely nothing: environment variables do not stay set
RUN . /root/.sdkman/bin/sdkman-init.sh
由于图像通常只包含一个应用程序及其运行时,因此您不需要更改正在使用的运行时或编译器版本的能力。我的 Docker 文件示例将其作为 ARG
传递,因此您可以在 Docker 文件中更改它或传递 docker build --build-arg KOTLIN_VERSION=...
选项以使用不同的版本。
Ubuntu Dockerfile
中的 SDKMAN
tl;博士
sdk
命令不是二进制文件,而是加载到内存中的 bash 脚本
- Shell 会话是一个“进程”,这意味着环境变量和声明的 shell 函数仅在 shell 会话存在期间存在;仅持续
RUN
命令。
- 手动调整您的
PATH
RUN apt-get update && apt-get install curl bash unzip zip -y
RUN curl -s "https://get.sdkman.io" | bash
RUN source "$HOME/.sdkman/bin/sdkman-init.sh" \
&& sdk install java 8.0.275-amzn \
&& sdk install sbt 1.4.2 \
&& sdk install scala 2.12.12
ENV PATH=/root/.sdkman/candidates/java/current/bin:$PATH
ENV PATH=/root/.sdkman/candidates/scala/current/bin:$PATH
ENV PATH=/root/.sdkman/candidates/sbt/current/bin:$PATH
完整版
哦,哇,这是一次探索之旅。每行下面都注释了为什么某些命令是 运行.
我学到了很多关于 unix 的工作原理和 sdkman 的工作原理以及 docker 的工作原理以及为什么三者的交集会产生非常不寻常的行为。
# I am using a multi-stage build so I am just copying the built artifacts
# from this stage to keep final image small.
FROM ubuntu:latest as ScalaBuild
# Switch from `sh -c` to `bash -c` as the shell behind a `RUN` command.
SHELL ["/bin/bash", "-c"]
# Usual updates
RUN apt-get update && apt-get upgrade -y
# Dependencies for sdkman installation
RUN apt-get install curl bash unzip zip -y
#Install sdkman
RUN curl -s "https://get.sdkman.io" | bash
# FUN FACTS:
# 1) the `sdk` command is not a binary but a bash script loaded into memory
# 2) Shell sessions are a "process", which means environment variables
# and declared shell function only exist for
# the duration that shell session exists
RUN source "$HOME/.sdkman/bin/sdkman-init.sh" \
&& sdk install java 8.0.275-amzn \
&& sdk install sbt 1.4.2 \
&& sdk install scala 2.12.12
# Once the real binaries exist these are
# the symlinked paths that need to exist on PATH
ENV PATH=/root/.sdkman/candidates/java/current/bin:$PATH
ENV PATH=/root/.sdkman/candidates/scala/current/bin:$PATH
ENV PATH=/root/.sdkman/candidates/sbt/current/bin:$PATH
# This is specific to running a minimal empty Scala project and packaging it
RUN touch build.sbt
RUN sbt compile
RUN sbt package
FROM alpine AS production
# setup production environment image here
COPY --from=ScalaBuild /root/target/scala-2.12/ $INSTALL_PATH
ENTRYPOINT ["java", "-cp", "$INSTALL_PATH", "your.main.classfile"]
我对 docker 的概念完全陌生。我正在创建以下 Dockerfile 作为练习。
FROM ubuntu:latest
MAINTAINER kesarling
RUN apt update && apt upgrade -y
RUN apt install nginx curl zip unzip -y
RUN apt install openjdk-14-jdk python3 python3-doc clang golang-go gcc g++ -y
RUN curl -s "https://get.sdkman.io" | bash
RUN bash /root/.sdkman/bin/sdkman-init.sh
RUN sdk version
RUN yes | bash -c 'sdk install kotlin'
CMD [ "echo","The development environment has now been fully setup with C, C++, JAVA, Python3, Go and Kotlin" ]
我正在使用 SDKMAN! to install Kotlin
. The problem initially was that instead of using RUN bash /root/.sdkman/bin/sdkman-init.sh
, I was using RUN source /root/.sdkman/bin/sdkman-init.sh
. However, it gave the error saying source
not found. So, I tried using RUN . /root/.sdkman/bin/sdkman-init.sh
, and it did not work. However, RUN bash /root/.sdkman/bin/sdkman-init.sh
seems 工作,因为没有给出任何错误并尝试 运行 下一个命令。然而, docker 然后给出错误说 sdk: not found
我哪里错了?
应该注意的是,这些步骤对我的主机发行版(我 运行 宁 docker 的发行版)非常有效,即 Pop!_OS 20.04
实际上脚本 /root/.sdkman/bin/sdkman-init.sh
来源 sdk
source 是 bash 的内置文件,而不是文件系统某处的二进制文件。
source命令执行当前shell中的文件。
每个 运行 指令将在当前图像之上的新层中执行任何命令并提交结果。
生成的提交映像将用于 Dockerfile 中的下一步。
试试这个:
FROM ubuntu:latest
MAINTAINER kesarling
RUN apt update && apt upgrade -y
RUN apt install nginx curl zip unzip -y
RUN apt install openjdk-14-jdk python3 python3-doc clang golang-go gcc g++ -y
RUN curl -s "https://get.sdkman.io" | bash
RUN /bin/bash -c "source /root/.sdkman/bin/sdkman-init.sh; sdk version; sdk install kotlin"
CMD [ "echo","The development environment has now been fully setup with C, C++, JAVA, Python3, Go and Kotlin" ]
通常您想避免在 Docker 中使用 "version manager" 类型的工具;最好安装您需要的特定版本的编译器或运行时。
就 Kotlin 而言,它是一个 JVM 应用程序 distributed as a zip file 因此安装应该相当容易:
FROM openjdk:15-slim
ARG KOTLIN_VERSION=1.3.72
# Get OS-level updates:
RUN apt-get update \
&& apt-get install --no-install-recommends --assume-yes \
curl \
unzip
# and if you need C/Python dependencies, those too
# Download and unpack Kotlin
RUN cd /opt \
&& curl -LO https://github.com/JetBrains/kotlin/releases/download/v${KOTLIN_VERSION}/kotlin-compiler-${KOTLIN_VERSION}.zip \
&& unzip kotlin-compiler-${KOTLIN_VERSION}.zip \
&& rm kotlin-compiler-${KOTLIN_VERSION}.zip
# Add its directory to $PATH
ENV PATH=/opt/kotlinc/bin:$PATH
版本管理器的真正问题在于它们严重依赖于工具设置环境变量。正如@JeevanRao 在 RUN
命令在单独的容器中的单独 shell 中运行,并且该命令中的任何环境变量设置都会丢失下一个命令。
# Does absolutely nothing: environment variables do not stay set
RUN . /root/.sdkman/bin/sdkman-init.sh
由于图像通常只包含一个应用程序及其运行时,因此您不需要更改正在使用的运行时或编译器版本的能力。我的 Docker 文件示例将其作为 ARG
传递,因此您可以在 Docker 文件中更改它或传递 docker build --build-arg KOTLIN_VERSION=...
选项以使用不同的版本。
Ubuntu Dockerfile
中的 SDKMANtl;博士
sdk
命令不是二进制文件,而是加载到内存中的 bash 脚本- Shell 会话是一个“进程”,这意味着环境变量和声明的 shell 函数仅在 shell 会话存在期间存在;仅持续
RUN
命令。 - 手动调整您的
PATH
RUN apt-get update && apt-get install curl bash unzip zip -y
RUN curl -s "https://get.sdkman.io" | bash
RUN source "$HOME/.sdkman/bin/sdkman-init.sh" \
&& sdk install java 8.0.275-amzn \
&& sdk install sbt 1.4.2 \
&& sdk install scala 2.12.12
ENV PATH=/root/.sdkman/candidates/java/current/bin:$PATH
ENV PATH=/root/.sdkman/candidates/scala/current/bin:$PATH
ENV PATH=/root/.sdkman/candidates/sbt/current/bin:$PATH
完整版
哦,哇,这是一次探索之旅。每行下面都注释了为什么某些命令是 运行.
我学到了很多关于 unix 的工作原理和 sdkman 的工作原理以及 docker 的工作原理以及为什么三者的交集会产生非常不寻常的行为。
# I am using a multi-stage build so I am just copying the built artifacts
# from this stage to keep final image small.
FROM ubuntu:latest as ScalaBuild
# Switch from `sh -c` to `bash -c` as the shell behind a `RUN` command.
SHELL ["/bin/bash", "-c"]
# Usual updates
RUN apt-get update && apt-get upgrade -y
# Dependencies for sdkman installation
RUN apt-get install curl bash unzip zip -y
#Install sdkman
RUN curl -s "https://get.sdkman.io" | bash
# FUN FACTS:
# 1) the `sdk` command is not a binary but a bash script loaded into memory
# 2) Shell sessions are a "process", which means environment variables
# and declared shell function only exist for
# the duration that shell session exists
RUN source "$HOME/.sdkman/bin/sdkman-init.sh" \
&& sdk install java 8.0.275-amzn \
&& sdk install sbt 1.4.2 \
&& sdk install scala 2.12.12
# Once the real binaries exist these are
# the symlinked paths that need to exist on PATH
ENV PATH=/root/.sdkman/candidates/java/current/bin:$PATH
ENV PATH=/root/.sdkman/candidates/scala/current/bin:$PATH
ENV PATH=/root/.sdkman/candidates/sbt/current/bin:$PATH
# This is specific to running a minimal empty Scala project and packaging it
RUN touch build.sbt
RUN sbt compile
RUN sbt package
FROM alpine AS production
# setup production environment image here
COPY --from=ScalaBuild /root/target/scala-2.12/ $INSTALL_PATH
ENTRYPOINT ["java", "-cp", "$INSTALL_PATH", "your.main.classfile"]