Docker每日一阅(3):创建自定义镜像
1 回顾
- 运行交互式的容器(
docker container run ... -i -t
) - 后台运行容器(
docker container run ... -d
) - 查看运行容器的日志(
docker container logs [container id]
) - 关闭正在运行的容器(
docker container stop [container id]
)
2 任务描述
docker container commit [container id]
创建镜像- Dockerfile创建镜像(
docker image build ...
)
注:上述的指令基本都可以简写,比如,docker image build ...
可以简写为docker build ...
,但我不喜欢这么做,因为你写全了就很清楚其中的逻辑了,比如,我们使用docker build实际上是用dockerfile build了一个image。而docker container commit
则是将一个container commit成为一个image。
3 通过commit语句创建镜像
首先,让我们把ubuntu:latest
image(镜像)pull下来,在交互模式下运行:
docker container run -ti ubuntu bash
注意,如果我们不在ubuntu
后面加冒号和版本号,系统就会默认pull下来最新版的镜像。terminal的结果如下:
Unable to find image 'ubuntu:latest' locally
latest: Pulling from library/ubuntu
7c3b88808835: Pull complete
Digest: sha256:8ae9bafbb64f63a50caab98fd3a5e37b3eb837a3e0780b78e5218e63193961f9
Status: Downloaded newer image for ubuntu:latest
root@f6732e34b067:/#
当我们再新建一个terminal,输入docker ps
的时候,我们就能看见一个正在运行的container(容器)了:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
f6732e34b067 ubuntu "bash" About a minute ago Up About a minute crazy_germain
我们可以在进入镜像后,实行和Ubuntu系统一模一样的指令,比如(我们随便装几个东西):
apt-get update; \
apt-get install -y figlet; \
figlet "hello docker"
关于apt-get update
,如果你觉得速度慢的话,可以在前面加两行(阿里的镜像源):
sed -i s@/archive.ubuntu.com/@/mirrors.aliyun.com/@g /etc/apt/sources.list; \
sed -i s@/deb.debian.org/@/mirrors.aliyun.com/@g /etc/apt/sources.list
然后我们退出容器(exit
),这个容器也就随之而停止运行了。
假设我们希望可以把这个容器(f6732e34b067
)封装成一个我们自定义的镜像,在本地环境我们可以:
docker container commit f6732e34b067
f6732e34b067
是container ID。这个时候,我们发现,本地系统多了一个镜像(docker image list
):
REPOSITORY TAG IMAGE ID CREATED SIZE
<none> <none> 118f27638e3f 4 seconds ago 108MB
ubuntu latest 2b4cba85892a 4 days ago 72.8MB
通过docker image tag 118f27638e3f ubuntu-cus
,我们对新建的镜像重命名:
REPOSITORY TAG IMAGE ID CREATED SIZE
ubuntu-cus latest 118f27638e3f 4 minutes ago 108MB
ubuntu latest 2b4cba85892a 4 days ago 72.8MB
在docker desktop里面,我们也能很明显地看到:
4 通过Dockerfile创建镜像
通过Dockerfile,我们通过一个文件提供了新建镜像的说明,这样管理更改变得更加容易,尤其是当镜像变得更大、更复杂时。这里我们列举一个简单的例子,先把代码跑通,把思路搞懂,然后我们在明天更加详细地进行解读。
我们在当前目录下创建一个main.py
文件,里面就一行字:print("Hello my friend")
。
然后,我们创建dockerfile,并且在里面写上:
FROM python:3.7-slim
RUN sed -i s@/archive.ubuntu.com/@/mirrors.aliyun.com/@g /etc/apt/sources.list
RUN sed -i s@/deb.debian.org/@/mirrors.aliyun.com/@g /etc/apt/sources.list \
&& apt-get clean \
&& apt-get update
COPY . /app
WORKDIR /app
CMD ["python","main.py"]
一共有五部分组成:
FROM
:基础镜像RUN
:相当于我们进入这个容器之后输入的命令COPY
:我们将此目录下的文件复制到镜像指定的目录下(/app
)WORKDIR
:此处制定容器启动时使用的目录CMD
:在容器启动是运行的命令
我们使用以下命令创建自定义的镜像:
docker image build -t python-cus:v1 .
-t
指的是tag,注意,最后有一个.
,不能漏掉,指的是读取此路径下的dockerfile。
等build完后,我们就能看到(docker image list
)新建的镜像了(注意这个镜像的tag):
REPOSITORY TAG IMAGE ID CREATED SIZE
python-cus v1 5986f9b52932 18 seconds ago 138MB
然后,让我们来run一下这个镜像:
docker container run python-cus:v1
在terminal中会返回Hello my friend
。
如果我们用交互式的方式进入这个容器:docker container run -it python-cus:v1 /bin/sh
,我们输入ls
和pwd
,能看到,确实就像dockerfile所写的那样,所有的本地当前路径下的文件都被复制到了/app
路径下,并且我们进入这个容器的位置就是/app
:
# ls
README.md dockerfile img index.js main.py
# pwd
/app