When you’re packaging your Python application in a Docker image, you’ll often use a virtualenv
.For example, you might be doing a multi-stage build in order to get smaller images.
Since you’re using a virtualenv
, you need to activate it—but if you’re just getting started with Dockerfiles, the naive way doesn’t work.And even if you do know how to do it, the usual method is repetitive and therefore error-prone.
There is a simpler way of activating a virtualenv, which I’ll demonstrate in this article.But first, we’ll go over some of the other, less elegant (or broken!) ways you might do it.
Then one can finally build and install with. Python3 setup.py build python3 setup.py install -user (you can drop the -user flag if you want to install it system-wide, but you'll need root privilege). Finally, one remove the extra swap and restore the default: sudo swapoff /var/swap.1 sudo rm /var/swap.1. Apt-get install openjdk-8-jdk automake autoconf apt-get install curl zip unzip libtool swig libpng-dev zlib1g-dev pkg-config git g wget xz-utils # For python2.7 apt-get install python-numpy python-dev python-pip python-mock # If using a virtual environment, omit the -user argument pip install -U -user kerasapplications1.0.8 -no-deps pip install -U -user keraspreprocessing1.1.0 -no. This is a dirty hack, not a solution. If your script is being run by the sh shell, but you want bash, the proper solution is either to have the sh process invoke bash as a one-off, e.g. Bash -c 'source /script.sh && ', or you could even go so far as to avoid bashisms (like source) entirely, and instead opt to only ever use valid POSIX equivalents, e.g.
Note: Outside the very specific topic under discussion, the Dockerfiles in this article are not examples of best practices, since the added complexity would obscure the main point of the article.
To ensure you’re writing secure, correct, fast Dockerfiles, consider my Python on Docker Production Handbook, which includes a packaging process and >70 best practices.
The method that doesn’t work
If you just blindly convert a shell script into a Dockerfile you will get something that looks right, but is actually broken:
Dockerfile Install Python 3d
It’s broken for two different reasons:
- Every
RUN
line in the Dockerfile is a different process.Runningactivate
in a separateRUN
has no effect on futureRUN
calls; for all practical purposes it’s a no-op. - When you run the resulting Docker image it will run the
CMD
—which also isn’t going to be run inside the virtualenv, since it too is unaffected by theRUN
processes.
The repetitive method that mostly works
One solution is to explicitly use the path to the binaries in the virtualenv.In this case we only have two repetitions, but in more complex situations you’ll need to do it over and over again.
Besides the lack of readability, repetition is a source of error.As you add more calls to Python programs, it’s easy to forget to add the magic /opt/venv/bin/
prefix.
It will (mostly) work though:
The only caveat is that if any Python process launches a sub-process, that sub-process will not run in the virtualenv.
The repetitive method that totally works
You can fix that by actually activating the virtualenv separately for each RUN
as well as the CMD
:
Dockerfile Install Python 365
(The exec
is there to get correct signal handling.)
The elegant method, in which we learn what activating actually does
It’s easy to think of activate
as some mysterious magic, a pentacle drawn in blood to keep Python safely trapped.But it’s just software, and fairly simple software at that.The virtualenv documentation will even tell you that activate
is “purely a convenience.”
If you go and read the code for activate
, it does a number of things:
- It figures out what shell you’re running.
- It adds a
deactivate
function to your shell, and messes around withpydoc
. - It changes the shell prompt to include the virtualenv name.
- It unsets the
PYTHONHOME
environment variable, if someone happened to set it. - It sets two environment variables:
VIRTUAL_ENV
andPATH
.
The first four are basically irrelevant to Docker usage, so that just leaves the last item.Most of the time VIRTUAL_ENV
has no effect, but some tools—e.g. the poetry
packaging tool—use it to detect whether you’re running inside a virtualenv.
The most important part is setting PATH
: PATH
is a list of directories which are searched for commands to run.activate
simply adds the virtualenv’s bin/
directory to the start of the list.
We can replace activate
by setting the appropriate environment variables: Docker’s ENV
command applies both subsequent RUN
s as well as to the CMD
.
The result is the following Dockerfile:
The virtualenv now automatically works for both RUN
and CMD
, without any repetition or need to remember anything.
Software isn’t magic
And there you have it: a version that is as simple as our original, broken version, but actually does the right thing.No repetition, and less scope for error.
When something seems needlessly complex, dig in and figures out how it works.The software you’re using might be simpler (or more simplistic) than you think, and with a little work you might come up with a more elegant solution.
方法一、docker pull tomcat
查找 Docker Hub 上的 Tomcat 镜像:
可以通过 Sort by 查看其他版本的 tomcat,默认是最新版本 tomcat:latest。
此外,我们还可以用 docker search tomcat 命令来查看可用版本:
这里我们拉取官方的镜像:
等待下载完成后,我们就可以在本地镜像列表里查到 REPOSITORY 为 tomcat 的镜像。
方法二、通过 Dockerfile 构建
创建Dockerfile
首先,创建目录tomcat,用于存放后面的相关东西。
webapps 目录将映射为 tomcat 容器配置的应用程序目录。
logs 目录将映射为 tomcat 容器的日志目录。
conf 目录里的配置文件将映射为 tomcat 容器的配置文件。
进入创建的 tomcat 目录,创建 Dockerfile。
通过 Dockerfile 创建一个镜像,替换成你自己的名字:
创建完成后,我们可以在本地的镜像列表里查找到刚刚创建的镜像:
使用 tomcat 镜像
运行容器
命令说明:
-p 8080:8080:将主机的 8080 端口映射到容器的 8080 端口。
-v $PWD/test:/usr/local/tomcat/webapps/test:将主机中当前目录下的 test 挂载到容器的 /test。
查看容器启动情况
通过浏览器访问