容器化入门(一)--docker入门
1. 什么是docker:docker是一种容器技术,是一种提供容器能力的工具。容器是一个集装箱,多个集装箱(容器)可以装载到一艘鲸鱼船(OS)上, 集装箱之间彼此隔离,集装箱彼此隔离、多个集装箱可以灵活搬运组装。
2. docker的安装:在ubuntu上安装dockeer
apt install -y docker.io
3. 启动docker服务:
service docker start
注意,如果是非root用户,需要将用户加入docker组
usermod -aG docker ${USER}
4. 查询docker基础信息:可以使用docker verison
和docker info
查询基础信息,包括版本、操作系统、当前的镜像数量等。同时,我们可以看到docker是C/S结构。
docker version
Client:
Version: 24.0.5
...
OS/Arch: linux/amd64
Server:
Engine:
Version: 24.0.5
...
OS/Arch: linux/amd64
...
containerd:
Version: 1.7.2
GitCommit:
runc:
Version: 1.1.7-0ubuntu1~22.04.2
GitCommit:
docker-init:
Version: 0.19.0
GitCommit:
docker info
Client:
Version: 24.0.5
Context: default
Debug Mode: false
Server:
Containers: 3
Running: 0
Paused: 0
Stopped: 3
Images: 3
Server Version: 24.0.5
Storage Driver: overlay2
Backing Filesystem: extfs
...
Operating System: Ubuntu 22.04.3 LTS
OSType: linux
Architecture: x86_64
CPUs: 2
Total Memory: 3.493GiB
...
5. 拉取镜像:使用docker pull
命令从镜像仓(默认为dockerHub)拉取别人做好的镜像
docker pull busybox
Using default tag: latest
latest: Pulling from library/busybox
Digest: sha256:c3839dd800b9eb7603340509769c43e146a74c63dca3045a8e7dc8ee07e53966
Status: Image is up to date for busybox:latest
docker.io/library/busybox:latest
6. 查询当前环境上所有的镜像:docker images
docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
alpine latest 05455a08881e 2 months ago 7.38MB
busybox latest ba5dc23f65d4 10 months ago 4.26MB
hello-world latest d2c94e258dcb 11 months ago 13.3kB
7. 镜像删除:docker image rm
或者docker rmi
8. 创建容器:docker run
docker run busybox echo hello word
hello word
9. 查询环境上的容器:docker -ps
docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
5ecc1cf9336a busybox "echo hello word" 49 seconds ago Exited (0) 48 seconds ago infallible_mendel
46363adef394 alpine "sh" 3 days ago Exited (0) 3 days ago pensive_raman
71516833d612 hello-world "/hello" 3 days ago Exited (0) 3 days ago unruffled_shannon
31287dc612eb busybox "echo hello word" 3 days ago Exited (0) 3 days ago elastic_lichterman
10. 容器删除:docker rm
根据容器ID删除容器
docker rm 7151
7151
11. 理解docker的核心概念:如下一张图体现了docker的C/S结构、镜像仓Registery、镜像、容器等核心概念:
同时,可以从一个官方的示例,感受几个关键概念之间的关系:我们直接通过docker run
命令运行容器时,它会先搞定镜像(本地有就用本地的、本地没有就从镜像仓下载),然后运行容器。
docker run hello-world
Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
c1ec31eb5944: Pull complete
Digest: sha256:53641cd209a4fecfc68e21a99871ce8c6920b2e7502df0a20671c6fccc73a7c6
Status: Downloaded newer image for hello-world:latest
Hello from Docker!
This message shows that your installation appears to be working correctly.
To generate this message, Docker took the following steps:
1. The Docker client contacted the Docker daemon.
2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
(amd64)
3. The Docker daemon created a new container from that image which runs the
executable that produces the output you are currently reading.
4. The Docker daemon streamed that output to the Docker client, which sent it
to your terminal.
To try something more ambitious, you can run an Ubuntu container with:
$ docker run -it ubuntu bash
Share images, automate workflows, and more with a free Docker ID:
https://hub.docker.com/
For more examples and ideas, visit:
https://docs.docker.com/get-started/
12. 容器技术的再理解:容器技术是动态的容器、静态的镜像、远端的镜像仓库的三者组合
13. 进入容器的内部,感受容器是怎么一个隔离的世界:我们运行一个操作系统alpine镜像,并私用-it
参数进入容器内部,执行相关命令,可以发现容器内部是一个完全隔离且完整的环境
docker run -it alpine sh
/ # cat /etc/os-release
NAME="Alpine Linux"
ID=alpine
VERSION_ID=3.19.1
PRETTY_NAME="Alpine Linux v3.19"
HOME_URL="https://alpinelinux.org/"
BUG_REPORT_URL="https://gitlab.alpinelinux.org/alpine/aports/-/issues"
/ # ps -ef
PID USER TIME COMMAND
1 root 0:00 sh
9 root 0:00 ps -ef
/ # exit
14. 容器技术的核心作用:使用容器技术,将程序运行在隔离的沙盒(SandBox)之中,给应用程序加上资源的隔离。
15. 容器技术和虚拟机的对比:我们知道虚拟机也能做到资源级别的隔离,两者之间的区别可以参考下图:容器直接利用了下层计算机的硬件和操作系统,比虚拟机少了一层,这意味着更好的资源利用效率和运行效率,但是隔离成程度不如虚拟机。
16. 容器的隔离实现的三大技术:
namespace:创建出独立的文件系统、主机名、进程号、网络等资源空间,给进程盖一间小板房 cgroup:实现对CPU、内存等资源的调配和控制,是小板房的天花板 chroot:可以更改进程的根root目录,限制文件系统的访问
17. 再说镜像和容器的关系:镜像是容器的静态只读描述文件,容器是操作系统根据镜像创建的动态隔离环境,可以说容器就是动态的镜像
18. 镜像和普通的tar、rpm等安装包的关系:镜像中不仅包括了应用程序本身、还包括了运行时的系统环境,具备更好的跨平台便携性和兼容性,是一种更高级、更便利的打包方式
19. 再说镜像:
镜像的完整名称:镜像完整名称有2个部分组成,名字和标签,中间用:连接。标签可以理解为版本号。如果不指定标签,默认使用latest标签。
docker pull alpine:3.15
docker pull ubuntu:jammy
docker pull nginx
docker pull redis
镜像ID:为了方便管理镜像,每个镜像都有一个唯一的ID,跟git里的commit ID一样,它也支持短路操作,我们在根据镜像ID删除镜像时只需要提供前3-4位即可。
docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
ubuntu jammy ca2b0f26964c 5 weeks ago 77.9MB
nginx latest 92b11f67642b 7 weeks ago 187MB
alpine latest 05455a08881e 2 months ago 7.38MB
redis latest 170a1e90f843 2 months ago 138MB
alpine 3.15 32b91e3161c8 4 months ago 5.59MB
busybox latest ba5dc23f65d4 10 months ago 4.26MB
hello-world latest d2c94e258dcb 11 months ago 13.3kB
镜像常用操作汇总:
命令 | 解释 |
---|---|
docker pull | 从远端仓库拉取镜像 |
docker images | 列出所有镜像 |
docker rmi | 删除镜像 |
20. 镜像操作补充:
docker run以及各类参数:基本用法是 docker run 设置参数 镜像名称or 镜像ID 附件的运行命令
。几个有用的参数:
参数 | 说明 |
---|---|
-it | 进入容器内部并打开shell |
-d | 让容器以后台方式运行 |
--name | 给容器一个名字 |
--rm | 容器停止后自动删除容器 |
docker run -d nginx:latest
docker run -d --name red_srv redis
docker run -it --name myubuntu ca2
docker exec执行容器里的另一个程序:最常见的用法是使用 -it
参数打开一个shell从而进入容器内部。后面紧跟着的容器的ID或者容器名
docker exec -it red_srv
使用docker stop停止容器:可以使用容器的ID或者容器名停止容器,多个容器空格分开即可
docker stop 47b0 c4f6
容器停止后并没有彻底销毁:容器停止后,可以使用 docker ps -a
查询到,我们可以使用docker start
继续启动运行。
docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
f85bee13a89f ca2 "/bin/bash" 13 minutes ago Exited (0) 12 minutes ago myubuntu-d
f26ec445ef0c ca2 "/bin/bash" 13 minutes ago Exited (0) 13 minutes ago myubuntu
47b07ca1098b redis "docker-entrypoint.s…" 14 minutes ago Exited (0) 3 minutes ago red_srv
c4f65e0dd250 nginx:latest "/docker-entrypoint.…" 15 minutes ago Exited (0) 3 minutes ago nice_hofstadter
b39cbe3fd881 alpine "sh" 5 hours ago Exited (0) 5 hours ago elated_franklin
18da077c10ba hello-world "/hello" 5 hours ago Exited (0) 5 hours ago tender_carver
5ecc1cf9336a busybox "echo hello word" 6 hours ago Exited (0) 6 hours ago infallible_mendel
46363adef394 alpine "sh" 3 days ago Exited (0) 3 days ago pensive_raman
31287dc612eb busybox "echo hello word" 3 days ago Exited (0) 3 days ago elastic_lichterman
容器删除docker rm:如果确实不再需要容器,可以使用命令删除。另外,如果你想在容器停止后被自动删除,可以在运行时指定 -rm
参数
docker rm f85 f26 47b
21. 镜像分层:镜像打包了应用程序还有它运行所依赖的环境,包括文件系统、环境变量等。为减少容器存储、传输的消耗,容器镜像的架构实际上时分层的。可以想象一种场景,如果有1000多款基于Ubuntu的应用打包成镜像,如果不进行分层、这1000多个镜像彼此之间会有多少重复的内容。
可以按下图理解:
22. 感受镜像的分层::可以使用docker inspect
查询镜像分层信息, 分层信息在FootFS中:
同时,我们的删除或者拉取镜像时也能看到分层的存在, docker会检查是否有重复的层,pull时如果本地已经存在某个层就不重复下载了,删除时如果层还被其他镜像复用就先不删除:
docker rmi nginx:latest
Untagged: nginx:latest
Untagged: nginx@sha256:6db391d1c0cfb30588ba0bf72ea999404f2764febf0f1f196acd5867ac7efa7e
Deleted: sha256:92b11f67642b62bbb98e7e49169c346b30e20cd3c1c034d31087e46924b9312e
Deleted: sha256:d9e826dbb4b3c5770fe92638baa8c6614f210d782a5d021a123fe9fa1f92c23d
Deleted: sha256:2a75285e888884bed4d630896c86ecd71739c6e82669e21ad7a050f33c9ac48d
Deleted: sha256:32bfe3f040358ab8f9872a63d4ddefdc68f35d991ca10a812cbac5912ae9f97b
Deleted: sha256:1330486eb62ea7e96f384961b77b0fc85f5d4422e761114ef3a72e7cb89751a4
Deleted: sha256:a375372209a0f2b2c697a52cce46bc41b495bf86184ae83dd5146e20c22078eb
Deleted: sha256:450787ca55caa59d0288de9cf36fc6b77d1b208a77eb837ec3d25b385f99cafb
23. Dockerfile是什么:Dockerfile是施工图纸、是指导文档,用于指示如何创建镜像。它是一个纯文本,记录了一系列构建指令,例如选择基础镜像、拷贝文件、运行脚本等,每个指令都会生成一个层。
24. 最简单的Dockerfile实践:如下Dockerfile选择基础的镜像busybox,并添加了一条容器启动时默认执行的命令:
# Dockerfile.mybusybox
FROM busybox
CMD echo "hello world"
可以使用docker build
命令创建镜像,-t
可以指定名称(包括标签),-f
指定Dockerfile, 同时后面还要指定构建的所在文件路径(称之为构建上下文)。
docker build -t mybosybox:qingming -f Dockerfile.mybusybox ./
DEPRECATED: The legacy builder is deprecated and will be removed in a future release.
Install the buildx component to build images with BuildKit:
https://docs.docker.com/go/buildx/
Sending build context to Docker daemon 406kB
Step 1/2 : FROM busybox
---> ba5dc23f65d4
Step 2/2 : CMD echo "hello world"
---> Running in 1835a5fe24f5
Removing intermediate container 1835a5fe24f5
---> 859d6d96a56e
Successfully built 859d6d96a56e
Successfully tagged mybosybox:qingming
我们可以使用docker run来运行下试试:
docker run --rm mybosybox:qingming
hello world
25. 编写正确、高效的Dockerfile:
FROM
选择基础镜像层:如果关注镜像的安全和大小,可以使用alpine镜像;如果关注运行稳定,可以使用ubuntu、centosCOPY
指令拷贝:可以把本机的相关文件拷贝到镜像中,但是必须是构建上下文中的路径,这个地方可以把构建上下文理解为构建时的根目录。因此,COPY /etc/hosts /tmp
是一条错误指令RUN
命令来执行shell指令:包括更新系统、安装依赖、构建编译程序等,有时候会非常复杂,多条shell指令使用&&连接,同时RUN
执行的命令过长,需要隔行时需要使用续行符\
,举例:
RUN apt-get update \
&& apt-get install -y \
curl make unzip \
&& cd /tmp \
&& mkdir xxx \
&& curl -fSL xxx.tar.gz -o xxx.tar.gz \
&& tar xvf xxx.tar.gz \
&& cd xxx \
&& ./config \
&& make \
&& make clean
针对 RUN
命令的另一个技巧:这种超长的RUN命令实在不好维护,可以先将构建的shell指令存储在一个sh脚本,然后先COPY
过来再执行RUN
命令
COPY setup.sh /tmp/
RUN cd /tmp && chmod +x setup.sh && ./setup.sh && rm setup.sh
在Dockerfile中使用变量:可以使用 ARG
和ENV
定义环境变量,两者的区别是ARG
定义的环境变量只在构建镜像时可见,容器运行时不可见;而ENV
定义的环境变量可以在构建时和容器运行时都可以使用
ARG IMAG_BASE="node"
ARG IMAG_TAG="alpine"
ENV PATH=$PATH:/tmp
ENV DEBUG+OFF
EXPOSE
声明容器对外使用的端口,可以指定对外暴露的端口、以及监听的协议
EXPOSE 443
EXPOSE 53/udp
尽量精简合并,否则会产生太多的层导致镜像臃肿 docker build
进一步说明:命令行docker只是一个客户端命令行,真正的构建在服务端构建,客户端将Dockerfile以及构建上下文目录打包上传。因为这样,所以COPY
指令才必须使用基于构建上下文的相对路径。为了避免将构建上下文中的无效文件上传导致构建效率低下,可以通过创建.dockerignore
文件的方式过滤掉不需要的文件
# dockerignore
*.swp
*.temp