#什么是Linux容器
由于虚拟机存在这些缺点,Linux 发展出了另一种虚拟化技术:**Linux容器(Linux Containers,缩写为LXC)**。
Linux 容器不是模拟一个完整的操作系统,而是对进程进行隔离。或者说,在正常进程的外面套了一个保护层。对于容器里面的进程来说,它接触到的各种资源都是虚拟的,从而实现与底层系统的隔离。
由于容器是进程级别的,相比虚拟机有很多优势:
- 启动快:容器里面的应用,直接就是底层系统的一个进程,而不是虚拟机内部的进程。所以,启动容器相当于启动本机的一个进程,而不是启动一个操作系统,速度就快很多。
- 资源占用少:容器只占用需要的资源,不占用那些没有用到的资源;虚拟机由于是完整的操作系统,不可避免要占用所有资源。另外,多个容器可以共享资源,虚拟机都是独享资源。
- 体积小:容器只要包含用到的组件即可,而虚拟机是整个操作系统的打包,所以容器文件比虚拟机文件要小很多。
总之,容器有点像轻量级的虚拟机,能够提供虚拟化的环境,但是成本开销小得多。
#Docker概述
Docker 属于 Linux 容器的一种封装,提供简单易用的容器使用接口。它是目前最流行的 Linux 容器解决方案。
Docker 将应用程序与该程序的依赖,打包在一个文件里面。运行这个文件,就会生成一个虚拟容器。程序在这个虚拟容器里运行,就好像在真实的物理机上运行一样。有了 Docker,就不用担心环境问题。
总体来说,Docker 的接口相当简单,用户可以方便地创建和使用容器,把自己的应用放入容器。容器还可以进行版本管理、复制、分享、修改,就像管理普通的代码一样。
#Docker的用途
Docker 的主要用途,目前有三大类。
提供一次性的环境:比如,本地测试他人的软件、持续集成的时候提供单元测试和构建的环境。
提供弹性的云服务:因为 Docker 容器可以随开随关,很适合动态扩容和缩容。
组建微服务架构:通过多个容器,一台机器可以跑多个服务,因此在本机就可以模拟出微服务架构。
#image文件(镜像)
Docker把应用程序及其依赖,打包在image文件里面。只有通过这个文件,才能生成Docker容器。image文件可以看作是容器的模板。Docker根据image文件生成容器的实例。同一个image文件,可以生成多个同时运行的容器实例。
image是二进制文件。实际开发中,一个image文件往往通过继承另一个image文件,加上一些个性化设置而生成。举例来说,你可以在Ubuntu的image基础上,往里面加入Apache服务器,形成你的image。
常用操作在速查中记录
image 文件是通用的,一台机器的 image 文件拷贝到另一台机器,照样可以使用。一般来说,为了节省时间,我们应该尽量使用别人制作好的 image 文件,而不是自己制作。即使要定制,也应该基于别人的 image 文件进行加工,而不是从零开始制作。
为了方便共享,image 文件制作完成后,可以上传到网上的仓库。Docker 的官方仓库Docker Hub是最重要、最常用的image仓库。此外,出售自己制作的image文件也是可以的。
#容器文件
image文件生成的容器实例,本身也是一个文件,称为容器文件。也就是说,一旦容器生成,就会同时存在两个文件:image文件和容器文件。而且关闭容器并不会删除容器文件,只是容器停止运行而已。要删除容器,需要使用相应的指令。
常用操作在速查中记录
#Dockerfile文件
学会使用image文件以后,接下来的问题就是,如何可以生成image文件?如果你要推广自己的软件,势必要自己制作image文件。
这就需要用到Dockerfile文件。它是一个文本文件,用来配置image。Docker根据该文件生成二进制的image文件。
#Dockerfile的编写
#.dockerignore文件
.dockerignore文件存放不包含入docker image的路经,例如:
.git
node_modules
npm-debug.log
#Dockerfile的基本结构
Dockerfile一般分为四部分:
- 基础镜像信息
- 维护者信息
- 镜像操作指令和容器启动时执行指令
- 注释(
#
为注释符)
#Dockerfile文件
Docker以从上到下的顺序运行Dockerfile的指令。为了指定基本映像,**第一条指令必须是FROM
**。一个声明以#
字符开头则被视为注释。可以在Docker文件中使用RUN
,CMD
,FROM
,EXPOSE
,ENV
等指令。
#常见的指令
FROM:指定基础镜像,必须为第一个命令
格式:
FROM [--platform=<platform>] <image> [AS <name>] FROM [--platform=<platform>] <image>[:<tag>] [AS <name>] FROM [--platform=<platform>] <image>[@<digest>] [AS <name>]
--platform
:指定镜像的平台,例如 linux/amd64、linux/arm64 或 windows/amd64。<image>
:基础镜像的名称。AS <name>
:镜像的别名。tag
:镜像的标签,默认为latest(用于指定版本号)。@digest
:镜像的摘要。
示例:
FROM mysql:5.6
MAINTAINER:维护者信息
格式:
MAINTAINER ["name"]
示例:
MAINTAINER Fumo
RUN:构建镜像时执行的命令
RUN用于在镜像容器中执行命令,其有以下两种命令执行方式:
shell执行
格式:
RUN <command>
exec执行
格式:
RUN ["executable","param1","param2"]
示例:
RUN apk update
RUN指令创建的中间镜像会被缓存,并会在下次构建中使用。如果不想使用这些缓存镜像,可以在构建时指定
--no-cache
参数,如:docker build --no-cache
中间镜像的产生
在使用命令build命令构建镜像时,比如:docker build -t demo4docker .
构建完成后,查看镜像:
docker images -a REPOSITORY TAG IMAGE ID CREATED SIZE demo4docker latest 09dc6a85ec83 6 days ago 776MB <none> <none> 912c358695d4 6 days ago 776MB <none> <none> affb7d9f6529 6 days ago 709MB <none> <none> b58ee21ac8b6 6 days ago 643MB
发现出现了几个没有既没有REPOSITORY也没有TAG的镜像,这些就是中间镜像(intermediate images).
有效
<none>
镜像和无效<none>
镜像有效none镜像:
Docker文件系统是由很多layers组成的,每个layer之间有父子关系,所有的 docker文件系统层默认都存储在/var/lib/docker/graph目录下,docker称之为图层数据库。
所以,这些<none>:<none>镜像是镜像的父层,必须存在的,并且不会造成硬盘空间占用问题。
无效none镜像
而docker还存在另一种没有被使用到的并且不会关联任何镜像的<none>:<none>镜像,这些镜像被称之为dangling images,这种类型的镜像会造成磁盘空间占用问题。
ADD:将本地文件添加到容器中
tar类型文件会自动解压(网络压缩资源不会被解压).可以访问网络资源,类似wget.
格式:
ADD <src> ... <dest> # 添加src至dest路径 ADD ["<src>",...,"<dest>"] # 用于支持包含空格的路径
示例:
ADD hom* /mydir/ # 添加所有以"hom"开头的文件 ADD hom?.txt /mydir/ # ?替代一个单字符,例如:"home.txt" ADD test relativeDir/ # 添加"test"到 relativeDir/ ADD test /absoluteDir/ # 添加 "test" 到 /absoluteDir/
COPY:功能类似ADD,但是是不会自动解压文件,也不能访问网络资源
CMD:构建容器后调用,也就是在容器启动时才进行调用。
格式:
CMD ["application","param1","param2",...] # 执行可执行文件 CMD ["param1","param2",...] # 设置了ENTRYPOINT,则直接调用ENTRYPOINT添加参数 CMD command param1 param2 ... # 执行shell内部命令
示例:
CMD echo "This is a test." | wc - CMD ["/usr/bin/wc","--help"]
ENTRYPOINT:配置容器,使其可执行化
配合
CMD
可省去application
,只使用参数.格式:
ENTRYPOINT ["executable", "param1", "param2"] # 可执行文件 ENTRYPOINT command param1 param2 # shell内部命令
示例:
FROM ubuntu ENTRYPOINT ["top", "-b"] CMD ["-c"]
ENTRYPOINT
与CMD
非常类似,不同的是通过docker run
执行的命令不会覆盖ENTRYPOINT(在启动容器后,CMD的参数是可以被以上命令覆盖的),而
docker run
命令中指定的任何参数,都会被当做附加参数再次传递给ENTRYPOINT,除非加上
--entrypoint
参数明确指出要覆盖其参数.Dockerfile中只允许有一个ENTRYPOINT命令,多指定时会覆盖前面的设置,而只执行最后的ENTRYPOINT指令.
LABEL:用于为镜像添加元数据
格式:
LABEL <key>=<value> <key>=<value> <key>=<value> ...
示例:
LABEL version="1.0" description="这是一个Web服务器" by="IT笔录"
使用LABEL指定元数据时,一条LABEL指定可以指定一或多条元数据,指定多条元数据时不同元数据之间通过空格分隔。推荐将所有的元数据通过一条LABEL指令指定,以免生成过多的中间镜像。
ENV:设置环境变量
格式:
ENV <key> <value> #<key>之后的所有内容均会被视为其<value>的组成部分.因此,这样写一次只能设置一个变量 ENV <key>=<value> ... #可以设置多个变量,每个变量为一个"<key>=<value>"的键值对,如果<key>中包含空格,可以使用\来进行转义,也可以通过""来进行标示;另外,反斜线也可以用于续行
示例:
ENV myName John Doe ENV myDog Rex The Dog ENV myCat=fluffy
EXPOSE:指定于外界交互的端口
格式:
EXPOSE <port> [<port>...]
示例:
EXPOSE 80 443 EXPOSE 8080 EXPOSE 11211/tcp 11211/udp
EXPOSE并不会让容器的端口访问到主机。要使其可访问,需要在
docker run
运行容器时通过-p来发布这些端口:docker run -p 8080:80 nginx # 将容器的80端口映射到宿主机的8080端口
VOLUME:用于指定持久化目录
格式:
VOLUME ["/path/to/dir"]
示例:
VOLUME ["/data"] VOLUME ["/var/www", "/var/log/apache2", "/etc/apache2"
一个卷可以存在于一个或多个容器的指定目录,该目录可以绕过联合文件系统,并具有以下功能:
- 卷可以容器间共享和重用
- 容器并不一定要和其它容器共享卷
- 修改卷后会立即生效
- 对卷的修改不会对镜像产生影响
- 卷会一直存在,直到没有任何容器在使用它
在Docker中,持久化存储是指在容器重启或删除后,数据仍然存在的方法。Docker提供了多种持久化存储方式,主要包括Volumes、Bind Mounts和Tmpfs
WORKDIR:设定工作目录
格式:
WORKDIR /path/to/workdir
示例:
WORKDIR /a (这时工作目录为/a) WORKDIR b (这时工作目录为/a/b) WORKDIR c (这时工作目录为/a/b/c) # 可知,多次使用该指令会叠加影响而非重置
通过WORKDIR设置工作目录后,Dockerfile中其后的命令RUN、CMD、ENTRYPOINT、ADD、COPY等命令都会在该目录下执行。在使用
docker run
运行容器时,可以通过-w参数覆盖构建时所设置的工作目录。USER:指定运行容器时的用户
可以指定用户名或UID,后续的RUN也会使用指定用户。使用USER指定用户时,可以使用用户名、UID或GID,或是两者的组合。当服务不需要管理员权限时,可以通过该命令指定运行用户。并且可以在之前创建所需要的用户
格式:
USER user USER user:group USER uid USER uid:gid USER user:gid USER uid:group
示例:
USER www
使用USER指定用户后,Dockerfile中其后的命令RUN、CMD、ENTRYPOINT都将使用该用户。镜像构建完成后,通过
docker run
运行容器时,可以通过-u参数来覆盖所指定的用户。ARG:用于指定传递给构建运行时的变量
格式:
ARG <name>[=<default value>]
示例:
ARG site ARG build_user=www
ONBUILD:用于设置镜像触发器
当所构建的镜像被用做其它镜像的基础镜像,该镜像中的触发器将会被触发
格式:
ONBUILD [INSTRUCTION]
示例:
ONBUILD ADD . /app/src ONBUILD RUN /usr/local/bin/python-build --dir /app/src
参考~🥰: