想法是有一个容器,其中包含所有小型项目,并根据参数运行。
当前情况是什么
我的项目文件夹如下:
├── MAIN_PROJECT_FOLDER
│ ├── PROJECT_SUB_CATEGORY1
│ ├── ├── PROJECT_NAME_FOLDER1
│ │ │ ├── run.sh
│ │ │ ├── main.py
│ │ │ ├── config.py
│ ├── ├── PROJECT_NAME_FOLDER2
│ │ │ ├── run.sh
│ │ │ ├── main.py
│ │ │ ├── config.py
│ ├── PROJECT_SUB_CATEGORY2
│ ├── ├── PROJECT_NAME_FOLDER1
│ │ │ ├── run.sh
│ │ │ ├── main.py
│ │ │ ├── config.py
│ ├── ├── PROJECT_NAME_FOLDER2
│ │ │ ├── run.sh
│ │ │ ├── main.py
│ │ │ ├── config.py
每个 run.sh 文件都具有prod / dev参数,可以像这样执行:
sudo ./run.sh prod = prod
sudo ./run.sh dev = dev
sudo ./run.sh = dev
创建另一个 .SH 文件或 Dockerfile 的方法是什么,该文件最后可以像这样执行:
sudo docker run CONTAINER_NAME PROJECT_NAME PROD/DEV
sudo docker run test_contaner test_project1 prod
sudo docker run test_contaner test_project1 dev
sudo docker run test_contaner test_project2 prod
... and so one
基本上,每个项目都是参数,并且prod / dev将以某种方式成为run.sh执行的一部分。
寻找最佳实践来实现这一目标。
答案 0 :(得分:2)
最佳做法通常是制作一张只做一件事的图像。在您的示例中,这意味着四个单独的Docker映像;每个目录都有自己的Dockerfile。
使用环境变量配置这样的设置也比使用命令行参数更容易。 https://12factor.net/ describe this之类的网站以及其他一些用于构建服务的做法。 (以我的经验,在像Docker Compose或Kubernetes这样的YAML规范中,添加另一个键/值环境对要比从多个不同的部分构建正确的命令行要容易得多。)
这将导致您出现类似的序列
sudo docker build -t me/cat1proj1 CATEGORY_1/PROJECT_1
sudo docker run -e ENVIRONMENT=prod me/cat1proj1
在架构上,Docker容器运行任何单个进程,并且绝对没有阻止您编写描述的包装器脚本的操作。该单个命令被指定为“入口点”和“命令”的组合。如果您同时指定了两者,则命令将作为参数传递给入口点。可以在Dockerfile CMD
中指定“命令”部分,但也可以在docker run
命令行中覆盖它。
如果您根本不编写任何特殊脚本,则可以运行(假设您已经COPY
将项目放置在正确的目录中)
sudo docker run test_image ./test_project1/run.sh prod
(我有几个项目是相同的应用程序,具有不同的脚本,它们以不同的方式启动它们-例如,Web服务器与具有相同代码的异步作业运行器-并仅使用备用启动脚本来启动它们这样)。
有一种模式可以使其他脚本成为ENTRYPOINT
,然后将“命令”解释为该脚本的参数。该命令仅作为参数$1
,$2
,"$@"
传递。这样做的问题是,它打破了一些常规的调试路径。
# "test_project1" "prod" passed as arguments to entrypoint script
sudo docker run test_image test_project1 prod
# But that breaks getting a debug shell
sudo docker run --rm -it test_image bash
# More complex commands get awkward
sudo docker run --rm --entrypoint=/bin/ls test_image -l /app
答案 1 :(得分:1)
我个人会使用Supervisor之类的工具,该工具可以在一个docker容器中运行。
在基于Ubuntu和Debian的发行版上安装supervisor
:
sudo apt install supervisor
启动supervisor
守护程序:
sudo service supervisor start
在/etc/supervisord/supervisord.conf
中,您将找到放置项目配置的位置:
[include]
files = /etc/supervisor/conf.d/*.conf
现在,您可以为主管创建配置并将其复制到/etc/supervisor/conf.d/
。项目supervisor
的示例PROJECT_1
配置:
project_1_supervisor.conf
:
[program:project_1_app]
command=/usr/bin/bash /project_1_path/run.sh prod
directory=/project_1_path/
autostart=true
autorestart=true
startretries=3
stderr_logfile=/var/log/project_1.err.log
stdout_logfile=/var/log/project_1.out.log
重启后,您的supervisor
:
sudo supervisorctl reread
sudo supervisorctl update
此后,您可以检查您的项目程序是否运行:
$ supervisorctl
project_1_app RUNNING pid 590, uptime 0:02:45
答案 2 :(得分:1)
我认为处理此问题的最佳方法是ENV,这是您正在寻找的完整示例。
这是目录结构
这是克隆上述应用程序并执行智能操作的最聪明的dockerfile;)这将需要四个env,默认情况下它将运行项目A。
ENV BASE_PATH="/opt/project"
此ENV用于克隆期间的项目基本路径
ENV PROJECT_PATH="/main/sub_folder_a/project_a"
此ENV用于项目路径,例如项目B
ENV SCRIPT_NAME="hello.py"
根据您的情况,此ENV将用于运行实际文件,可以是run.sh
或main.py
。
ENV SYSTEM_ENV=dev
此环境用于run.sh,它可以dev
或prod
FROM python:3.7.4-alpine3.10
WORKDIR /opt/project
# Required Tools
RUN apk add --no-cache supervisor git tree && \
mkdir -p /etc/supervisord.d/
# clone remote project or copy your own one
RUN echo "Starting remote clonning...."
RUN git clone https://github.com/Adiii717/python-demo-app.git /opt/project
RUN tree /opt/project
# ENV for start different project, can be overide at run time
ENV BASE_PATH="/opt/project"
ENV PROJECT_PATH="/main/sub_folder_a/project_a"
ENV SCRIPT_NAME="hello.py"
# possible dev or prod
ENV SYSTEM_ENV=dev
RUN chmod +x /opt/project/main/*/*/run.sh
# general config
RUN echo $'[supervisord] \n\
[unix_http_server] \n\
file = /tmp/supervisor.sock \n\
chmod = 0777 \n\
chown= nobody:nogroup \n\
[supervisord] \n\
logfile = /tmp/supervisord.log \n\
logfile_maxbytes = 50MB \n\
logfile_backups=10 \n\
loglevel = info \n\
pidfile = /tmp/supervisord.pid \n\
nodaemon = true \n\
umask = 022 \n\
identifier = supervisor \n\
[supervisorctl] \n\
serverurl = unix:///tmp/supervisor.sock \n\
[rpcinterface:supervisor] \n\
supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface \n\
[include] \n\
files = /etc/supervisord.d/*.conf' >> /etc/supervisord.conf
# script supervisord Config
RUN echo $'[supervisord] \n\
nodaemon=true \n\
[program:run_project ] \n\
command= /run_project.sh \n\
stdout_logfile=/dev/fd/1 \n\
stdout_logfile_maxbytes=0MB \n\
stderr_logfile_maxbytes = 0 \n\
stderr_logfile=/dev/fd/2 \n\
redirect_stderr=true \n\
autorestart=false \n\
startretries=0 \n\
exitcodes=0 ' >> /etc/supervisord.d/run_project.conf
RUN echo $'#!/bin/ash \n\
echo -e "\x1B[31m starting project having name ${BASE_PATH}${PROJECT_PATH}/${SCRIPT_NAME} \x1B[0m" \n\
fullfilename=${BASE_PATH}${PROJECT_PATH}/${SCRIPT_NAME} \n\
filename=$(basename "$fullfilename") \n\
extension="${filename##*.}" \n\
if [[ ${extension} == "sh" ]];then \n\
sh ${BASE_PATH}${PROJECT_PATH}/${SCRIPT_NAME} ${SYSTEM_ENV} \n\
else \n\
python ${BASE_PATH}${PROJECT_PATH}/${SCRIPT_NAME} \n\
fi ' >> /run_project.sh
RUN chmod +x /run_project.sh
EXPOSE 9080 8000 9088 80
ENTRYPOINT ["supervisord", "--nodaemon", "--configuration", "/etc/supervisord.conf"]
构建docker映像
docker build -t multipy .
运行Docker容器
docker run --rm -it multipy
这将默认运行project a
对于项目b,您的命令将为
docker run --rm -it --env PROJECT_PATH=/main/sub_folder_b/project_b --env SCRIPT_NAME=hello.py multipy
要运行您的run.sh
bash文件命令,将是
docker run --rm -it --env SCRIPT_NAME=run.sh multipy
这是一些日志