无法在 nginx:alpine 中安装 bash
Cannot install bash in nginx:alpine
我有以下 Dockerfile:
# => Build container
FROM node:14-alpine AS builder
WORKDIR /app
# split the dependecies from our source code so docker builds can cache this step
# (unless we actually change dependencies)
COPY package.json yarn.lock ./
RUN yarn install
COPY . ./
RUN yarn build
# => Run container
FROM nginx:alpine
# Nginx config
WORKDIR /usr/share/nginx/html
RUN rm -rf ./*
COPY ./nginx/nginx.conf /etc/nginx/conf.d/default.conf
# Default port exposure
EXPOSE 8080
# Copy .env file and shell script to container
COPY --from=builder /app/dist .
COPY ./env.sh .
COPY .env .
USER root
# Add bash
RUN apk update && apk add --no-cache bash
# Make our shell script executable
RUN chmod +x env.sh
# Start Nginx server
CMD ["/bin/bash", "-c", "/usr/share/nginx/html/env.sh && nginx -g \"daemon off;\""]
但是当我尝试 运行 它时,我在尝试添加 bash
时遇到以下错误:
------
> [stage-1 8/9] RUN apk update && apk add --no-cache bash:
#19 0.294 fetch https://dl-cdn.alpinelinux.org/alpine/v3.14/main/x86_64/APKINDEX.tar.gz
#19 0.358 140186175183688:error:1416F086:SSL routines:tls_process_server_certificate:certificate verify failed:ssl/statem/statem_clnt.c:1914:
#19 0.360 fetch https://dl-cdn.alpinelinux.org/alpine/v3.14/community/x86_64/APKINDEX.tar.gz
#19 0.360 ERROR: https://dl-cdn.alpinelinux.org/alpine/v3.14/main: Permission denied
#19 0.360 WARNING: Ignoring https://dl-cdn.alpinelinux.org/alpine/v3.14/main: No such file or directory
#19 0.405 140186175183688:error:1416F086:SSL routines:tls_process_server_certificate:certificate verify failed:ssl/statem/statem_clnt.c:1914:
#19 0.407 ERROR: https://dl-cdn.alpinelinux.org/alpine/v3.14/community: Permission denied
#19 0.407 WARNING: Ignoring https://dl-cdn.alpinelinux.org/alpine/v3.14/community: No such file or directory
#19 0.408 2 errors; 42 distinct packages available
------
executor failed running [/bin/sh -c apk update && apk add --no-cache bash]: exit code: 2
我需要添加以执行此脚本:
#!/bin/bash
# Recreate config file
rm -rf ./env-config.js
touch ./env-config.js
# Add assignment
echo "window._env_ = {" >> ./env-config.js
# Read each line in .env file
# Each line represents key=value pairs
while read -r line || [[ -n "$line" ]];
do
# Split env variables by character `=`
if printf '%s\n' "$line" | grep -q -e '='; then
varname=$(printf '%s\n' "$line" | sed -e 's/=.*//')
varvalue=$(printf '%s\n' "$line" | sed -e 's/^[^=]*=//')
fi
# Read value of current variable if exists as Environment variable
value=$(printf '%s\n' "${!varname}")
# Otherwise use value from .env file
[[ -z $value ]] && value=${varvalue}
# Append configuration property to JS file
echo " $varname: \"$value\"," >> ./env-config.js
done < .env
echo "}" >> ./env-config.js
根据我的阅读,添加 USER root
应该可以解决这个问题,但在这种情况下不会。
关于如何解决的任何想法?
你应该可以使用/bin/sh
作为一个标准的谍影重重shell;此外,您应该能够避免 CMD
行中的 sh -c
包装器。
首先,使用 POSIX shell syntax. Scanning over the script, it seems like it is almost okay as-is; change the first line to #!/bin/sh
, and correct the non-standard ${!varname}
expansion (also see Dynamic variable names in Bash)
重写脚本
# Read value of current variable if exists as Environment variable
value=$(sh -c "echo $$varname")
# Otherwise use value from .env file
[[ -z $value ]] && value=${varvalue}
您可以尝试使用 alpine
或 busybox
具有更严格 shell 的图像进行测试,或者使用 bash 设置 POSIXLY_CORRECT
环境变量.
其次,using ENTRYPOINT
and CMD
together 有一个合理的标准模式。 CMD
作为参数传递给 ENTRYPOINT
,因此如果 ENTRYPOINT
以 exec "$@"
结尾,它将用该命令替换自身。
#!/bin/sh
# ^^ not bash
# Recreate config file
...
echo "window._env_ = {" >> ./env-config.js
...
echo "}" >> ./env-config.js
# Run the main container CMD
exec "$@"
现在,在您的 Docker 文件中,您不需要安装 GNU bash,因为您没有使用它,但您确实需要正确拆分 ENTRYPOINT
和 CMD
.
ENTRYPOINT ["/usr/share/nginx/html/env.sh"] # must be JSON-array syntax
CMD ["nginx", "-g", "daemon off;"] # can be either syntax
顺便说一句,cmd1 && cmd2
语法是基本的 shell 语法而不是 bash 扩展,所以你可以写 CMD ["/bin/sh", "-c", "cmd1 && cmd2"]
;但是,如果您编写的命令没有 JSON 数组语法,Docker 将为您插入 sh -c
包装器。您几乎不需要在 Docker 文件中写出 sh -c
。
我有以下 Dockerfile:
# => Build container
FROM node:14-alpine AS builder
WORKDIR /app
# split the dependecies from our source code so docker builds can cache this step
# (unless we actually change dependencies)
COPY package.json yarn.lock ./
RUN yarn install
COPY . ./
RUN yarn build
# => Run container
FROM nginx:alpine
# Nginx config
WORKDIR /usr/share/nginx/html
RUN rm -rf ./*
COPY ./nginx/nginx.conf /etc/nginx/conf.d/default.conf
# Default port exposure
EXPOSE 8080
# Copy .env file and shell script to container
COPY --from=builder /app/dist .
COPY ./env.sh .
COPY .env .
USER root
# Add bash
RUN apk update && apk add --no-cache bash
# Make our shell script executable
RUN chmod +x env.sh
# Start Nginx server
CMD ["/bin/bash", "-c", "/usr/share/nginx/html/env.sh && nginx -g \"daemon off;\""]
但是当我尝试 运行 它时,我在尝试添加 bash
时遇到以下错误:
------
> [stage-1 8/9] RUN apk update && apk add --no-cache bash:
#19 0.294 fetch https://dl-cdn.alpinelinux.org/alpine/v3.14/main/x86_64/APKINDEX.tar.gz
#19 0.358 140186175183688:error:1416F086:SSL routines:tls_process_server_certificate:certificate verify failed:ssl/statem/statem_clnt.c:1914:
#19 0.360 fetch https://dl-cdn.alpinelinux.org/alpine/v3.14/community/x86_64/APKINDEX.tar.gz
#19 0.360 ERROR: https://dl-cdn.alpinelinux.org/alpine/v3.14/main: Permission denied
#19 0.360 WARNING: Ignoring https://dl-cdn.alpinelinux.org/alpine/v3.14/main: No such file or directory
#19 0.405 140186175183688:error:1416F086:SSL routines:tls_process_server_certificate:certificate verify failed:ssl/statem/statem_clnt.c:1914:
#19 0.407 ERROR: https://dl-cdn.alpinelinux.org/alpine/v3.14/community: Permission denied
#19 0.407 WARNING: Ignoring https://dl-cdn.alpinelinux.org/alpine/v3.14/community: No such file or directory
#19 0.408 2 errors; 42 distinct packages available
------
executor failed running [/bin/sh -c apk update && apk add --no-cache bash]: exit code: 2
我需要添加以执行此脚本:
#!/bin/bash
# Recreate config file
rm -rf ./env-config.js
touch ./env-config.js
# Add assignment
echo "window._env_ = {" >> ./env-config.js
# Read each line in .env file
# Each line represents key=value pairs
while read -r line || [[ -n "$line" ]];
do
# Split env variables by character `=`
if printf '%s\n' "$line" | grep -q -e '='; then
varname=$(printf '%s\n' "$line" | sed -e 's/=.*//')
varvalue=$(printf '%s\n' "$line" | sed -e 's/^[^=]*=//')
fi
# Read value of current variable if exists as Environment variable
value=$(printf '%s\n' "${!varname}")
# Otherwise use value from .env file
[[ -z $value ]] && value=${varvalue}
# Append configuration property to JS file
echo " $varname: \"$value\"," >> ./env-config.js
done < .env
echo "}" >> ./env-config.js
根据我的阅读,添加 USER root
应该可以解决这个问题,但在这种情况下不会。
关于如何解决的任何想法?
你应该可以使用/bin/sh
作为一个标准的谍影重重shell;此外,您应该能够避免 CMD
行中的 sh -c
包装器。
首先,使用 POSIX shell syntax. Scanning over the script, it seems like it is almost okay as-is; change the first line to #!/bin/sh
, and correct the non-standard ${!varname}
expansion (also see Dynamic variable names in Bash)
# Read value of current variable if exists as Environment variable
value=$(sh -c "echo $$varname")
# Otherwise use value from .env file
[[ -z $value ]] && value=${varvalue}
您可以尝试使用 alpine
或 busybox
具有更严格 shell 的图像进行测试,或者使用 bash 设置 POSIXLY_CORRECT
环境变量.
其次,using ENTRYPOINT
and CMD
together 有一个合理的标准模式。 CMD
作为参数传递给 ENTRYPOINT
,因此如果 ENTRYPOINT
以 exec "$@"
结尾,它将用该命令替换自身。
#!/bin/sh
# ^^ not bash
# Recreate config file
...
echo "window._env_ = {" >> ./env-config.js
...
echo "}" >> ./env-config.js
# Run the main container CMD
exec "$@"
现在,在您的 Docker 文件中,您不需要安装 GNU bash,因为您没有使用它,但您确实需要正确拆分 ENTRYPOINT
和 CMD
.
ENTRYPOINT ["/usr/share/nginx/html/env.sh"] # must be JSON-array syntax
CMD ["nginx", "-g", "daemon off;"] # can be either syntax
顺便说一句,cmd1 && cmd2
语法是基本的 shell 语法而不是 bash 扩展,所以你可以写 CMD ["/bin/sh", "-c", "cmd1 && cmd2"]
;但是,如果您编写的命令没有 JSON 数组语法,Docker 将为您插入 sh -c
包装器。您几乎不需要在 Docker 文件中写出 sh -c
。