Docker快速入门
一、Doker快速使用
1.1 构建一个容器
拉取并使用docker的ubuntu镜像构建一个交互式的容器。
sudo docker run --name containerName -i -t ubuntu /bin/bash
参数解释:
``–name`是对于容器的命名
-i
保证容器的STDIN开启,保证持续的标准输入;
-t
为docker为容器分配一个tty终端
ubuntu
提供的是镜像名,先从本机查找之后,若无则去dockerHub上查找
/bin/bash
告知容器需要运行的命令
1.2 关闭容器与查看
在容器内键入exit
可以退出容器,之后在宿主机上可以通过使用
docker ps -a
来查看所拥有的全部容器。
1.3 启动并附着到容器
当知道容器的名字或者uuid的时候可以使用
sudo docker start containerName
sudo docker start UUID
来重新运行容器,重新运行的容器会沿用docker run
时候的命令,此时我们可以使用
sudo docker attach containerName
重新进入容器的会话。
1.4 使用非交互的守护式容器
有时候需要长期运行的容器,并不需要交互式会话,这时候我们会选择使用守护式容器(daemonized container)
sudo docker run --name containerName -d ubuntu /bin/sh
参数解释:
-d
将容器放在后台运行
1.5 查看守护式容器信息
对于在后台运行的守护式容器,我们可以获取容器的日志。
sudo docker logs -f containerName
参数解释:
-f
跟踪式运行
在运行容器的时候可以选用不同的日志驱动,常见的有
- json-file(默认)
- syslog:禁用docker log命令,并将所有日志输出都重定向到syslog。
- none:禁用一切日志
另外也可以通过使用docker top name
来查看到容器内的进程,可以使用docker stats name
来查看容器内部的硬件统计信息。
1.6 在守护式容器内部运行新的进程
在docker1.3之后可以使用docker exec
命令在容器内部额外启动新的进程
sudo docker exec -d containerName command
参数解释:
-d
表示在后台运行
command
是需要的命令
或者使用如下命令来启动前端的程序
sudo docker exec -i -t containerName command
1.7 守护式容器的关闭与重启
对于后台运行的守护式容器,可以使用docker stop containerName
发送SIGTERM信号进行停止。
而对于快速停止则可以使用docker kill
命令发送SIGKILL信号。
容器有可能因为某种错误而停止,可以通过在run的时候进行标记,来使其自动重启。
sudo docker run --name containerName --restrat=always -i -t ubuntu /bin/bash
这个属性具有两种标价,可以使用always来设置为自动重启,也可以使用
on-failure:n
中的n来指定最多重启次数。
1.8 删除容器
当容器已经不在使用的时候,可以通过rm命令
sudo docker rm -f containerName
参数解释:
使用f可以无需关闭容器强行删除,不然则需要在删除容器前先关闭当前的容器。
删除所有容器需要多个命令的组合,如下:
sudo docker rm `sudo docker ps -a -q`
在ps命令中,可以使用
-a
获得所有的容器,而-q
的标志使得这条命令只返回id表
二、Docker的镜像与容器
2.1 基本概念介绍
Docker镜像是由文件系统叠加而成,最底端是一个引导文件系统(bootfs)。接下来第二层是root文件系统(rootfs),这可以是一种或者多种操作系统。接下来docker会使用联合加载(union mount)的技术在root文件系统层上加载更多的只读系统,将各层文件系统叠加到一起。
这样的文件系统就是docker的镜像,最底下是一个基础镜像,而最上面会叠加一个读写文件系统,我们的程序会在这上面运行。使用的机制是写时复制,当修改一个文件的时候,会从底层复制这个读写层,在对其修改后隐藏下面的层。
2.2 管理镜像
可以使用sudo docker images
来列出当前所拥有的全部镜像,也可以使用
sudo docker images imageName
来查看本地同一个镜像名,不同版本(tag)的镜像。
镜像可以从仓库下载,默认的仓库会保存在Docker公司的Registry服务(Docker hub)下。每一个仓库都可以存放很多镜像,如Ubuntu仓库中会保存很多版本的镜像。
Docker Hub中有两种类型的仓库,分别是用户仓库(user repository)和顶层仓库(top-level repository)
用户仓库:userName/repositoryName
顶层仓库:Name
对于镜像文件,可以在使用run
之前使用docker拉取相应的镜像文件
sudo docker pull image:tag
参数解释
tag是image的版本,都在image的仓库之中。
2.3 查找镜像
我们可以通过使用search命令查找,所有可用的公共镜像。
sudo docker search imageName
这个命令会在docker上查找所有包含这个名字的镜像,我们可以拉去这些镜像并用其创建容器。
2.4 构建镜像
我们修改、更新和、管理镜像提供了两种方法。
- 使用
docker commit
命令(不推荐) - 使用
docker build
命令和dockerfile文件
在使用commit
命令的时候,我们先启动容器,做自己需要的更改退出容器,之后可运行
sudo docker commit -m "informations" -a "author" id repositoryName/imageName:tag
参数解释:
id:容器的标识符
-m
:指定新创建的镜像的提交信息
-a
:作者的信息repositoryName:选择的镜像仓库名称,通常为自己的用户名
imageName:镜像名
tag:标签名
注:这个命令提交的只是创建容器的镜像和容器当前状态的差别部分,使得更新十分轻量。
2.5 基于Dockerfile来构建镜像
使用基于DSL语法的dockerfile可以构建镜像,具有更高的重复性、透明性、幂等性。
2.5.1 快速尝试
首先可以创建如下的基础Dockerfile
# Version:0.0.1
From ubuntu
LABEL shenvinci maintainer="shenvinci@gmail.com"
RUN apt-get update && apt-get install -y nginx
EXPOSE 80
参数解释:
FROM
指定了所用的基础镜像
LABLE
可以告知镜像的作者以及邮箱
EXPOSE
可以指定应用程序使用容器的端口
在使用Dockfile构建镜像的时候,每一条指令都会创建一个新的镜像并提交,这样的操作逻辑即使在某一条失败而没有正常的结束,仍可以保留一个最后的镜像文件,可以用于调试。
默认情况下RUN
指令会使用命令包装器来执行,而对于不希望在Shell中运行的可以使用exec
格式来运行指令,这种方式运行使用一个数组来指定要运行的命令和每一个参数。
RUN ["apt-get","install","-y","nginx"]
当有dockerfile存在后,我们可以使用build命令来构建镜像文件。
docker build -t="repositoryName/imageName:tag" path
参数解释:
-t=
用于表示镜像的仓库名,镜像名以及标签
path
表示dockerfile所处的路径,这个路径也可以是远端仓库的位置
当使用构建的时候,dokerfile所处的上下文也会被传送到docker守护进程,如果有不想被传送的文件可以通过设置.dockerignore
文件来选择需要过滤匹配的文件。
2.5.2 Dockerfile的缓存逻辑
因为在构建镜像的过程中,每一个步骤都会被构建为单独的镜像层,当再次使用dockerfile进行构建的时候,就会从最新一次有发生更改的部分继续进行构建。如果需要忽略所有缓存,则可以使用--no-cache
命令来忽略所有缓存构建。
因为这种特性,我们通常选择相似的docker模板,这样就可以不必重新运行前面的指令来构建镜像,而对于需要刷新的部分,我们可以在之前插入环境变量语句,如
# Version:0.0.2
From ubuntu
LABEL shenvinci maintainer="shenvinci@gmail.com"
ENV REFRESHED_AT 2021-9-30
RUN apt-get update && apt-get install -y nginx
EXPOSE 80
参数解释
ENV
:设置了一个名为REFRESHED_AT的环境变量,指明了模板最新更新的时间,当更改时间后,后面的所有内容都会重新运行,使得包可以进行刷新。
2.5.3 查看与使用新的镜像
docker images repositoryName/imageName
docker history repositoryName/imageName
上面的第一个代码,可以查看自己构建的镜像的具体状况,而需要查看具体的构建全步骤过程,则可以使用下面的,查看到每一层的镜像文件以及相应的构建指令。
当我们使用这种自己构建的镜像运行时候,我们的run
命令需要加入新的内容
sudo docker run -d -p 127.0.0.1:8080:80 --name containerName repositoryName/imageName command
参数解释
-p
参数用于配置容器与宿主机的端口链接,如上述命令是把容器的80映射到宿主机127ip的8080端口上,当其中有参数被省略时,则会使用默认(随机)参数。当我们使用-P
的时候,会将容器的80绑定到一个宿主机随机端口,然后将dockerfile中EXPOSE指定的端口全部公开.
command
命令是直接在容器内运行的内容,通常用于打开需要的服务
我们可以使用docker ps -l
命令查看所有容器被映射的端口,也可以使用docker port uuid 80
查看这一容器80端口被映射到的宿主机端口位置。
2.6 Dockerfile指令
2.6.1 CMD
CMD指令用于指定容器启动时运行的命令(而RUN指令的只是在被构建时候运行),通常的格式为
CMD ["/bin/bash","-l"]
Docker一直推荐使用数组来设置需要执行的命令。同时我们需要牢记docker run
命令会覆盖CMD指令,同时要知道再Dockerfile中只能指定一条CMD指令,如果指定了多条则只有最后一条会被运行。
2.6.2 ENTRYPOINT
这个指令与CMD十分类似,而最大的区别在于其不会被命令中的指令覆盖
实际上所有的指令都会作为参数传入
ENTRYPOINT
中。
在使用这个指令的时候我们也会使用数组进行内容的传输
ENTRYPOINT ["/usr/sbin/nginx","-g","daemon off;"]
将这个命令,CMD
命令以及docker run
时选择的命令进行组合,可以得到默认参数的使用方法。
ENTRYPOINT ["/usr/sbin/nginx"]
CMD["-h"]
docker run -t -i repositoryName/imageName -g "daemon off;"
在默认情况下,会使用CMD命令中的-h参数,但在run的时候如果添加了新的参数,则会对其进行覆盖,以此实现默认参数的效果。
2.6.3 WORKDIR
这个指令可以在容器内部设置一个工作目录(切换内部的路径),用于CMD
与ENTRYPOINT
的执行。
WORKDIR /opt/webapp
CMD command
我们为command指令设置了路径
我们可以在run的时候通过-w
来覆盖工作的目录。
2.6.4 ENV
在镜像构建的过程中设置环境变量,这个环境变量可以在之后任何RUN指令中使用,就如同在命令前面指定了环境变量的前缀。
ENV RVM_PATH=/home/rvm TARGET_FIR=/opt/app
RUN gem install unicorn
WORKDIR $TARGET_FIR
参数解释:
设置了
RVM_PATH
与TARGET_FIR
两个环境变量,第一个可以为第二条RUN
指令提供前缀条件,变成如RVM_PATH=/home/rvm RUN gem install unicorn
而第二个则被用于提供了工作目录的位置。
注意:在Dockerfile中设置的环境变量都是在容器中具有持久化作用的,而如果只是在使用docker run
时候加入-e
来传递的环境变量则只在运行的时候有效。
2.6.5 USER
指定这个镜像以什么用户去运行,可以通过指定用户名(或uid)以及组(或gid)来选择。如果不选择默认会使用root
USER user
USER user:group
USER uid
USER uid:gid
2.6.6 VOLUME
用来向基于镜像创建的容器添加卷(可以存在于一个或者多个容器内的特定的目录),卷可以绕过联合文件系统并提供共享以及持久化的数据功能,卷的功能可以让我们**把数据、数据库或者其他内容添加到镜像而不是将内容提交到镜像。**通常用来测试容器和内部的应用程序代码。管理日志,处理内部数据库。
VOLUME ["/opt/project",/data]
参数解释:
为基于此镜像的任何容器创建了这两个挂载点。
2.6.7 ADD
将构建环境下的文件和目录复制到镜像之中,需要指定源文件位置和目的文件位置两个参数。
ADD contentPath aimPath
参数解释:
contentPath
是上下文的文件,通过末尾的字符来判断是目录还是文件,如果以/
结尾的就被认为是目录。在处理本地文件的时候,当归档文件被指定为源文件的时候,docker会把文件自动解开。(以URL指定目前不行)
aimPath
是镜像内的目标位置,如果目录不存在的话,会自动创建这样的新目录,其模式为文件模式为0755。
ADD
指令会使得构建的缓存变得无效,当添加后,所有的后续指令都需要重新进行构建。
2.6.8 COPY
与ADD
命令基本类似,但不会做文件提取以及解压等方面的内容,需要注意,所有的文件源路径都必须是在Dockerfile的相对文件夹下,不能复制这个目录以外其他目录的内容。
2.6.9 LABEL
这个指令可以为docker添加元数据,以键值对的形式展现出来。
LABEL version="1.0" location="China" type="Web"
推荐将所有的元数据都放入一条LABEL指令中,防止构建过多的镜像层。
我们可以通过docker inspect repositoryName/imageName
来查看容器内部的标签。
2.6.10 STOPSIGNAL
用于设置停止容器的时候发送什么系统调用信号给容器,这信号必须是内核系统调用表中合法的数字(9)或者SIGNAME格式中信号名称(如SIGKILL)。
2.6.11 ARG
用来定义可以在docker build
命令运行的时候传递给构建运行的变量,在构建时候可以根据dockerfile中定义过的变量进行传递
ARG build
ARG webapp_user=user
参数解释
定义了两个变量,第二个给了一个默认值,接下来可以在使用
docker build --build-arg build=1234
这样的命令来添加参数
2.6.12 ONBUILD
为当前的镜像添加触发器,当这个镜像被用作为其他镜像的基础镜像的时候,该镜像中的触发器会被执行。触发器会在下一个继承他的镜像的FORM
之后添加这些被触发的指令
ONBUILD ADD . /app/src
ONBUILD RUN cd /app
此处使用了两条命令,当有新的镜像Dockerfile继承当前的镜像时候,运行后回在FORM之后插入这两句话
注意:触发器只能被子镜像继承,当孙镜像运行时候则不会再进行继承。
2.7 删除自己的镜像
当我们不再需要一个镜像的时候,我们可以使用
sudo docker rmi repositoryName/imageName1 repositoryName/imageName2
来删除这个镜像,这一行为同时也会删除构建这个镜像的时候所产生的每一层镜像,后面也可以不断往后罗列镜像,这将删除这镜像列表里面全部的镜像。
2.8 Docker镜像的管理
我们可以把自己在本地构建完成的镜像推送到远程仓库(默认为DockerHub),通过使用
docker push repositoryName/imageName
就可以将自己的镜像上传至自己的远程仓库之中。
而除了这种方式,我们可以选择使用自动构建,这只需要将Github中含有Dockerfile文件的仓库链接到Docker Hub上,当我们向github推送时候,dockerhub也会自动更新(但这种方式就不可以使用docker push
来发布镜像)。
三、Docker实战操作
3.1 卷的挂载
有些时候外面不想把应用或者代码构建到镜像之中
- 同时对代码进行开发与测试
- 代码改动十分频繁,不想在开发过程中重构镜像
- 希望在多个容器之间共享代码
这时候我们就需要使用docker的卷挂在来实现,通过在运行容器的时候使用-v 宿主机目录:容器内目录:读写权限
来对本地与容器内的文件进行映射挂载。
docker run -d -p 80 --name web -v ./web:/var/www/html/website:ro repositoryName/imageName2 cmd
3.2 容器的链接
3.2.1Docker Networking
Docker Networking允许用户创建自己的网络,容器可以通过这个网络来互相通信,接下来是一些常用的管理指令。
sudo docker network create name #创建一个桥接网络并命名为name
sudo docker network inspect name #查看这个网络的信息
sudo docker network ls # 查看当前系统中的所有网络
sudo docker network rm # 删除一个网络
当有网络后,我们在运行容器时候可以加上–net=name
的标识符,把容器加入指定的网络之中。在网络内部启动的容器,docker会感知到所有在这个网络下的容器,并把这些信息都通过到当前容器的/etc/hosts
文件把所有地址都保存到DNS之中。
在网络之中的任何容器的地址,都可以通过hostname.app
的形式被解析,当一个容器重启的时候,它们的IP地址也会被自动更新(即对容器底层的修改不会对程序的正常工作产生影响)
3.2.2 Docker链接
在使用run
对容器进行运行的时候,我们增加--link containerName:linkName
创建了客户联系,此时被运行的容器被称为客户容器,而另一个则是服务,我们为这个服务增加了linkName作为别名,这可以让我们一致的访问容器公开的信息,且无须关注底层容器的名字。
将容器连接在一起可以让客户容器任意访问另一个容器,而不用对外公开端口。
四、Docker编配和服务发现
4.1 Docker Compose
Dockers Compose通常被用于简单的Docker容器编配使用YAML
文件定义一组需要启动的容器,以及容器运行时的属性,这些容器可以被称为是服务。我们可以很快的使用Compose来创建多容器应用栈。
安装:使用pip install -U docker-compose
可以进行最新版本的快速安装
当应用的镜像构建完成之后,我们可以使用Compose来创建需要的服务,并定义启动时候需要的属性,这些属性都会被放置与YAML
文件之中,样例:
web:
image : shenvinci/flask
command : python app.py
ports :
- "5000:5000"
volumes :
- .:/composeapp
links :
- redis
redis:
image : redis
参数解释:
开启了分别名为
web
与redis
的两个容器文件,并为其配置了相应的参数,Compose会使用这些参数生产多个容器并组成相应的容器栈。
当切换至有YAML
文件的目录下后,我们有一些常用的指令
docker-compose up -d # 在后台运行容器栈
docker-compose ps # 列出本地docker-compose.yml 文件中正在运行的所有服务
docker-compose stop # 停止正在运行的所有服务
docker-compose kill # 强制杀死正在运行中的服务
docker-compose rm # 删除docker-compose服务