Docker实践
阅读量
0
阅读人次
0
以往使用Docker,就是单纯的使用通过Docker构建的各种应用。或者自己构建Docker镜像,用于项目源码的构建,用作就当作虚拟机来看待。
Tini
tini 是一个最小化的 init
系统,运行在容器内部,用于启动一个子进程,并等待进程退出时清理僵尸和执行信号转发。 这是一个替代庞大复杂的systemd体系的解决方案。
使用 tini 有什么好处?作者在 Issues 下给出了一个回答。
docker 容器运行必须有一个前台进程, 如果没有前台进程执行,容器认为空闲,就会自行退出。所以我们 Dockerfile
中的 CMD
或者 ENTRYPOINT
指定的进行,不能执行完就退出,否则容器再执行完指定的命令后,就会自行退出。
在常见的Dockerfile中,一般我们会见到如下使用:
ENTRYPOINT ["tini","--","/opt/act/run.sh"]
这行的目的是,以 tini 作为进程ID为1
的进程,然后调用 /opt/act/run.sh
脚本运行。
--
用于分隔 tini
的命令行选项和传递给 tini
执行的命令的参数,防止 tini
本身的选项与由 tini
运行的命令的选项之间的歧义。这也是 Linux 中一种常见的约定。
例如:
tini -s -- ls --help
--
左侧的 -s
作为选项被 tini 接受,右侧的 --help
tini 是不会去处理的,意即 --
右侧的ls --help
作为命令执行。
Ubuntu
用作开发使用。
FROM ubuntu:24.04
LABEL maintainer="amass <168062547@qq.com>"
ENV DEBIAN_FRONTEND=noninteractive
RUN sed -i 's@//.*archive.ubuntu.com@//mirrors.ustc.edu.cn@g' /etc/apt/sources.list.d/ubuntu.sources \
&& apt update \
&& apt install -y gcc g++ cmake ninja-build pkg-config openssh-server git nano gpg ca-certificates \
wget curl rsync lsb-release ubuntu-keyring gnupg2 libssl-dev \
&& install -m 0755 -d /etc/apt/keyrings \
&& curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc \
&& chmod a+r /etc/apt/keyrings/docker.asc \
&& echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null \
&& wget -O - https://openresty.org/package/pubkey.gpg | gpg --dearmor -o /usr/share/keyrings/openresty.gpg \
&& echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/openresty.gpg] http://openresty.org/package/ubuntu $(lsb_release -sc) main" | tee /etc/apt/sources.list.d/openresty.list > /dev/null \
&& curl -fsSL https://deb.nodesource.com/setup_lts.x | bash - \
&& apt update \
&& apt install -y docker-ce-cli openresty nodejs
RUN git config --global core.quotepath false \
&& git config --global user.email "168062547@qq.com" \
&& git config --global user.name "amass"
RUN mkdir /var/run/sshd \
&& sed -i 's/#Port 22/Port 1022/' /etc/ssh/sshd_config \
&& sed -i 's/#PubkeyAuthentication yes/PubkeyAuthentication yes/' /etc/ssh/sshd_config \
&& mkdir -p /root/.ssh \
&& wget https://frp-by1.wwvvww.cn:25538/nextcloud/s/id_ed25519/download -O /root/.ssh/authorized_keys \
&& chmod 600 /root/.ssh/authorized_keys && chown root:root /root/.ssh/authorized_keys
EXPOSE 1022
RUN git config --global user.email "168062547@qq.com" \
&& git config --global user.name "amass"
RUN cd /root \
&& wget https://frp-by1.wwvvww.cn:25538/nextcloud/s/boost_1_86_0/download -O boost_1_86_0.tar.gz \
&& tar xvf boost_1_86_0.tar.gz > /dev/null \
&& cd /root/boost_1_86_0 \
&& ./bootstrap.sh --prefix=/opt/Libraries/boost_1_86_0 \
&& ./b2 install -q --prefix=/opt/Libraries/boost_1_86_0 threading=multi link=shared runtime-link=shared variant=release cxxstd=17 cxxflags=-fPIC cflags=-fPIC \
&& rm -fr /root/boost_1_86_0*
ENV LD_LIBRARY_PATH=/opt/Libraries/boost_1_86_0/lib:$LD_LIBRARY_PATH
CMD ["service", "ssh", "start", "-D"]
构建镜像:
docker build --progress=plain -f Dockerfile -t ubuntu_dev:24.04 .
frp
构建frp用作内网穿透,除了集成frpc以外,还打算集成nginx。使用场景如下:我们在内网部署了 jellyfin 服务,但是其 https 端口使能起来比较麻烦,这样我们可以将 nginx 作为 https 服务器,然后再将 nginx 作为反向代理将请求转发至 jellyfin。
FROM amd64/alpine:3.18
LABEL maintainer="amass <168062547@qq.com>"
ENV FRP_VERSION 0.58.1
RUN apk add openssl curl ca-certificates \
&& wget 'http://openresty.org/package/admin@openresty.com-5ea678a6.rsa.pub' \
&& mv 'admin@openresty.com-5ea678a6.rsa.pub' /etc/apk/keys/ \
&& . /etc/os-release \
&& MAJOR_VER=`echo $VERSION_ID | sed 's/\.[0-9]\+$//'` \
&& echo "http://openresty.org/package/alpine/v$MAJOR_VER/main" | tee -a /etc/apk/repositories \
&& apk update \
&& apk add openresty openresty-resty openresty-opm \
&& opm get bungle/lua-resty-session
RUN cd /root \
&& wget --no-check-certificate -c https://github.com/fatedier/frp/releases/download/v${FRP_VERSION}/frp_${FRP_VERSION}_linux_amd64.tar.gz \
&& tar zxvf frp_${FRP_VERSION}_linux_amd64.tar.gz \
&& cd frp_${FRP_VERSION}_linux_amd64/ \
&& cp frpc /usr/bin/ \
&& mkdir -p /etc/frp \
&& cp frpc.toml /etc/frp \
&& cd /root \
&& rm frp_${FRP_VERSION}_linux_amd64.tar.gz \
&& rm -rf frp_${FRP_VERSION}_linux_amd64/
ENTRYPOINT if [ -d /app ]; then cd /app && openresty -p /app; fi; /usr/bin/frpc -c /etc/frp/frpc.toml
使用:
docker run --restart=always --network host -d --name wwooww_frpc \
-e TZ="Asia/Shanghai" \
-v /mnt/user/appdata/frpc/wwooww_frpc.toml:/etc/frp/frpc.toml \
-v /mnt/user/appdata/frpc:/app \
registry.cn-shenzhen.aliyuncs.com/amass_toolset/frpc:0.60.0
docker run --restart=always --network host -d --name codeserver_frpc \
-e TZ="Asia/Shanghai" \
-v /mnt/user/appdata/frpc/wwooww_frpc.ini:/etc/frp/frpc.ini \
registry.cn-shenzhen.aliyuncs.com/amass_toolset/frpc:0.49.0
docker run --restart=always --network host -d --name frpc \
-e TZ="Asia/Shanghai" \
-v /mnt/user/appdata/frpc/frpc.toml:/etc/frp/frpc.toml \
registry.cn-shenzhen.aliyuncs.com/amass_toolset/frpc:0.60.0
Gitea Act Runner
在 unRaid 应用市场提供的 Act Runner 不支持 Docker-in-Docker 功能,那么实际作用就很小了,为了满足实际需求,我们自己构建。
FROM ubuntu:22.04
LABEL maintainer="amass <168062547@qq.com>"
ENV DEBIAN_FRONTEND=noninteractive
RUN sed -i 's@//.*archive.ubuntu.com@//mirrors.ustc.edu.cn@g' /etc/apt/sources.list \
&& apt update \
&& apt install -y ca-certificates curl git tini \
&& curl https://gitea.com/gitea/act_runner/releases/download/v0.2.6/act_runner-0.2.6-linux-amd64 -o /usr/local/bin/act_runner \
&& chmod +x /usr/local/bin/act_runner \
&& install -m 0755 -d /etc/apt/keyrings \
&& curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc \
&& chmod a+r /etc/apt/keyrings/docker.asc \
&& echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null \
&& apt update \
&& apt install -y docker-ce-cli
COPY resources/act_runner.sh /opt/act/run.sh
ENTRYPOINT ["tini","--","/opt/act/run.sh"]
#!/usr/bin/env bash
if [[ ! -d /data ]]; then
mkdir -p /data
fi
cd /data
RUNNER_STATE_FILE=${RUNNER_STATE_FILE:-'.runner'}
CONFIG_ARG=""
if [[ ! -z "${CONFIG_FILE}" ]]; then
CONFIG_ARG="--config ${CONFIG_FILE}"
fi
EXTRA_ARGS=""
if [[ ! -z "${GITEA_RUNNER_LABELS}" ]]; then
EXTRA_ARGS="${EXTRA_ARGS} --labels ${GITEA_RUNNER_LABELS}"
fi
# In case no token is set, it's possible to read the token from a file, i.e. a Docker Secret
if [[ -z "${GITEA_RUNNER_REGISTRATION_TOKEN}" ]] && [[ -f "${GITEA_RUNNER_REGISTRATION_TOKEN_FILE}" ]]; then
GITEA_RUNNER_REGISTRATION_TOKEN=$(cat "${GITEA_RUNNER_REGISTRATION_TOKEN_FILE}")
fi
# Use the same ENV variable names as https://github.com/vegardit/docker-gitea-act-runner
test -f "$RUNNER_STATE_FILE" || echo "$RUNNER_STATE_FILE is missing or not a regular file"
if [[ ! -s "$RUNNER_STATE_FILE" ]]; then
try=$((try + 1))
success=0
# The point of this loop is to make it simple, when running both act_runner and gitea in docker,
# for the act_runner to wait a moment for gitea to become available before erroring out. Within
# the context of a single docker-compose, something similar could be done via healthchecks, but
# this is more flexible.
while [[ $success -eq 0 ]] && [[ $try -lt ${GITEA_MAX_REG_ATTEMPTS:-10} ]]; do
act_runner register \
--instance "${GITEA_INSTANCE_URL}" \
--token "${GITEA_RUNNER_REGISTRATION_TOKEN}" \
--name "${GITEA_RUNNER_NAME:-`hostname`}" \
${CONFIG_ARG} ${EXTRA_ARGS} --no-interactive 2>&1 | tee /tmp/reg.log
cat /tmp/reg.log | grep 'Runner registered successfully' > /dev/null
if [[ $? -eq 0 ]]; then
echo "SUCCESS"
success=1
else
echo "Waiting to retry ..."
sleep 5
fi
done
fi
# Prevent reading the token from the act_runner process
unset GITEA_RUNNER_REGISTRATION_TOKEN
unset GITEA_RUNNER_REGISTRATION_TOKEN_FILE
act_runner daemon ${CONFIG_ARG}
使用:
rm -fr /mnt/user/appdata/gitea-runner
docker run -d --name='gitea-runner' --restart=always \
-e TZ="Asia/Shanghai" \
-e 'GITEA_RUNNER_REGISTRATION_TOKEN'='your_token' \
-e 'GITEA_RUNNER_NAME'='unraid_act_runner' \
-e 'GITEA_RUNNER_LABELS'='ubuntu-24.04,ubuntu-latest' \
-e 'GITEA_INSTANCE_URL'='https://amass.fun/gitea' \
-v /var/run/docker.sock:/var/run/docker.sock \
-v /mnt/user/appdata/gitea-runner/data:/data \
registry.cn-shenzhen.aliyuncs.com/amass_toolset/act_runner:0.2.11
GITEA_RUNNER_REGISTRATION_TOKEN:在Actions设置的创建 Runner
的下拉框可以找到。
nanopb(i386)
在做嵌入式开发的时候,有时候会碰到很古老的一些应用工具,它只有 i386 的二进制可执行文件。有时候为了保持宿主机的干净,我们不想开启对 i386 可执行文件的支持,然后至少需要安装 libc6:i386
、libstdc++6:i386
等一些安装包,这时我们也可以使用 docker 来帮助我们,让宿主机尽量保持 干净。
以 nanopb 为例,这是笔者在工作中碰到的一个工具。
FROM ubuntu:22.04
LABEL maintainer 168062547@qq.com
ENV DEBIAN_FRONTEND=noninteractive
RUN sed -i "s@http://.*archive.ubuntu.com@http://mirrors.tuna.tsinghua.edu.cn@g" /etc/apt/sources.list && \
sed -i "s@http://.*security.ubuntu.com@http://mirrors.tuna.tsinghua.edu.cn@g" /etc/apt/sources.list && \
dpkg --add-architecture i386 && \
apt-get update && \
apt-get install -y wget libc6:i386 libstdc++6:i386
RUN cd /opt && \
wget https://jpa.kapsi.fi/nanopb/download/nanopb-0.3.9.3-linux-x86.tar.gz && \
tar xvf nanopb-0.3.9.3-linux-x86.tar.gz && \
rm nanopb-0.3.9.3-linux-x86.tar.gz
ENV PATH="${PATH}:/opt/nanopb-0.3.9.3-linux-x86/generator-bin"
这样,我们就可以执行以下命令,将 .proto
文件输出我们所需要的源代码文件:
docker run --rm -v .:/app -w /app nanopb:0.3.9.3 protoc --nanopb_out=. ./PacketModel_all.proto
镜像上传
当我们制作好镜像后,可以上传到阿里云的容器镜像服务
中。
这里我们以制作好的ubuntu
镜像为例,在 仓库管理➡镜像仓库➡创建镜像仓库
里创建名为ubuntu
的仓库。然后在对应的仓库页,有如何拉取推送的说明与示例:
docker login --username=168062547@qq.com registry.cn-shenzhen.aliyuncs.com
docker tag [ImageId] registry.cn-shenzhen.aliyuncs.com/amass_toolset/ubuntu:[镜像版本号]
docker push registry.cn-shenzhen.aliyuncs.com/amass_toolset/ubuntu:[镜像版本号]