文章目录
1 Docker容器初识
1.1 是什么?
基于Go的开源的轻量级、可移植的容器项目
1.2 能做什么?
为应用服务,提供开发、运行、测试、部署一系列的服务。简而言之,就是可以利用docker来编译运行我们的项目,每个容器就是一个服务,可以快速部署我们的服务。
- 借助镜像进行项目的快速部署(部署环境)
- 每个容器运行一个应用,不同容器相互隔离(隔离性)
- 每个运行的容器都是基本最小的虚拟机环境(运行资源)
- 在服务资源升级和回滚上,借助升级扩容,一键能完成成千上百的服务集群的快速部署。(伸缩扩容)
1.3 怎么做的?
Linux容器是对进程的隔离,好比给正常的进程套了一个保护层,容器里的进程接触的各种资源都是虚拟的,从而实现与底层系统的隔离。
它相比虚拟机来说,因为是进程级别的,所以有很多优势:启动快、资源占用少、体积小; 容器与宿主机是共享系统内核的。
Docker属于Linux容器一种封装,提供简单易用的容器使用接口。
Docker的接口相当简单,用户可以方便地创建和使用容器,把自己的应用放入容器。
1.4 Docker与虚拟机的区别
传统方式是在硬件层面实现虚拟化,需要有额外的虚拟机管理应用和虚拟机操作系统层。
Docker容器是在操作系统层面上实现虚拟化,直接复用本地主机的操作系统,因此更加轻量级。
2 Docker的三大核心概念
2.1 镜像与容器的关系
镜像自身是只读的。容器从镜像启动的时候,会在镜像的最上层创建一个只读层。
容器(Container):镜像(Image)和容器(Container)的关系,就像是面向对象程序设计中的类和实例一样,镜像是静态的定义,容器是镜像运行时的实体。容器可以被创建、启动、停止、删除、暂停等。(容器是独立运行的一个或一组应用,是镜像运行时的实体。
)
2.2 镜像与仓库的关系
仓库(Repository):仓库可看成一个代码控制中心,用来保存镜像。
类似于git管理仓库的设计方法。
2.3 Docker镜像的分层结构
一个docker镜像由多个可读的镜像层组成,然后运行的容器会在这个docker的镜像上面多加一层可写的容器层,任何的对文件的更改都只存在此容器层。因此任何对容器的操作均不会影响到镜像。
3 使用Docker镜像
几个问题:
- 如何使用pull命令从Docker Hub仓库中下载镜像到本地?
- 如何查看本地已有的镜像信息和管理镜像标签?
- 如何在远端仓库使用search命令进行搜索和过滤?
- 如何删除镜像标签和镜像文件?
- 如何创建用户定制的镜像并且保存为外部文件?
- 如何往Docker Hub仓库中推送自己的镜像?
3.1 获取镜像
可以使用docker[image]pull命令直接从Docker Hub镜像源来下载镜像。该命令的格式为docker[image]pull NAME[: TAG]。
完整的命令为: docker pull 镜像所在仓库地址:镜像版本号,如
$docker pull hub.c.163.com/public/ubuntu:18.04
默认使用的是Docker Hub官方仓库的最新版本号
下载镜像到本地后,即可随时使用该镜像了,例如利用容器,在其中运行bash应用,执行打印“Hello World”命令:
$ docker run -it ubuntu:18.04 bash
root@65663247040f:/# echo "Hello World"
Hello World
root@65663247040f:/# exit
3.2 查看镜像信息
-
使用images列出镜像
docker images 或者 docker image ls -
使用tag命令添加镜像标签
docker tag ubuntu:latest myubuntu:latest
类似链接,快捷方式的作用, 我们可以直接使用myubuntu:latest来使用ubuntu:latest -
使用inspect命令查看镜像详细信息
docker [image] inspect ubuntu:18.04 -
使用history命令查看镜像历史
既然镜像文件由多个层组成,那么怎么知道各个层的内容具体是什么呢?这时候可以使用history子命令,该命令将列出各层的创建信息。
docker history ubuntu:18.04
3.3 查找镜像
使用 docker search 命令可以搜索Docker Hub官方仓库中的镜像。语法为docker search [option] keyword。支持的命令选项主要包括:
-f, --filter: 过滤输出内容
例子:
搜索官方带nginx的镜像:
docker search --filter=is-official=true nginx
3.4 删除和清理镜像
Docker镜像的rm和prune子命令
- 使用标签删除镜像
docker rmi myubuntu:18.04 - 使用镜像id删除镜像
docker rm a21c0840213e - 清理镜像
docker image prune
3.5 创建镜像
有三种创建方式:
- 基于已有容器创建
举个例子:
已有容器
$ docker run -it ubuntu:18.04 /bin/bash
root@a925cb40b3f0:/# touch test
root@a925cb40b3f0:/# exit
使用docker [container] commit来提交为一个新的镜像。提交时可以使用ID 或名称来指定容器
$ docker [container] commit -m "Added a new file" -a "Docker Newbee" a925cb40b3f0test:0.1
9e9c814023bcffc3e67e892a235afe61b02f66a947d2747f724bd317dda02f27
-m message
-a author
-
基于本地模板导入
cat ubuntu-18.04-minial.tar.gz | docker import ubuntu:18.04 -
基于Dockerfile创建
利用给定的指令基于某个父镜像创建新镜像的过程
举个例子:
runoob@runoob:~$ cat Dockerfile
FROM centos:6.7
MAINTAINER Fisher "fisher@sudops.com"
RUN /bin/echo 'root:123456' |chpasswd
RUN useradd runoob
RUN /bin/echo 'runoob:123456' |chpasswd
RUN /bin/echo -e "LANG=\"en_US.UTF-8\"" >/etc/default/local
EXPOSE 22
EXPOSE 80
CMD /usr/sbin/sshd -D
每一个指令都会在镜像上创建一个新的层,每一个指令的前缀都必须是大写的。
第一条FROM,指定使用哪个镜像源
RUN 指令告诉docker 在镜像内执行命令,安装了什么。。。
然后,我们使用 Dockerfile 文件,通过 docker build 命令来构建一个镜像。
runoob@runoob:~$ docker build -t runoob/centos:6.7 .
Sending build context to Docker daemon 17.92 kB
Step 1 : FROM centos:6.7
---> d95b5ca17cc3
Step 2 : MAINTAINER Fisher "fisher@sudops.com"
---> Using cache
---> 0c92299c6f03
Step 3 : RUN /bin/echo 'root:123456' |chpasswd
---> Using cache
---> 0397ce2fbd0a
Step 4 : RUN useradd runoob
......
3.6 存出和载入镜像
- 存出
例如,导出本地的 ubuntu:18.04 镜像为文件ubuntu18.04.tar,
如下所示:
$ docker images
REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE
ubuntu 18.04 0458a4468cbc 2 weeks ago 188 MB
$ docker save -o ubuntu_18.04.tar ubuntu:18.04
之后,用户就可以过复制 ubuntu_18.04.tar文件将该镜像分享给他人。
- 载入
可以使用docker [image] load将导出的tar文件再导人到本地镜像库。支持 -i、-input string 选项,从指定文件中读人镜像内容。
例如,从文件ubuntu_18.04.tar导人镜像到本地镜像列表,如下所示:
$ docker load -i ubuntu_18.04.tar
或者:
$ docker load < ubuntu_18.04.tar
3.7 上传镜像
用户给本地的镜像如test:latest添加标签user/test:latest,然后push上传
$ docker tag test:latest user/test:latest
$ docker push user/test:latest
The push refers to a repository [
[docker.io/user/test]
Sending image list
Please
login prior to push:
Username:
Password:
Email:
4 操作Docker容器
Docker容器的create、start、run、wait 和 logs子命令。
4.1 新建容器和运行容器
-
新建容器
$ docker create -it ubuntu:latest af8f4f922dafee22c8fe6cd2ae11d16e25087d61flblfa55b36e94db7ef45178 $ docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES af8f4f922daf ubuntu:latest "/bin/bash" 17 seconds ago Created silly_euler
-
新建并启动一个容器
$ docker run -it ubuntu /bin/bash
参数说明:
-i: 交互式操作。
-t: 终端。
ubuntu: ubuntu 镜像。
/bin/bash:放在镜像名后的是命令,这里我们希望有个交互式 Shell,因此用的是 /bin/bash。
要退出终端,直接输入 exit:
当利用docker [container] run来创建并启动容器时,Docker在
后台运行的标准包括:- 检查本地是否存在指定的镜像,不存在就从公有仓库下载;
- 利用镜像创建一个容器,并启动该容器;
- 分配一个文件系统给容器,并在只读的镜像层外面挂载一层可读写层;
- 从宿主主机配置的网桥接口中桥接一个虚拟接口到容器中去;
- 从网桥的地址池配置一个IP 地址给容器;
- 执行用户指定的应用程序;
- 执行完毕后容器被自动终止。
-
启动一个已经停止的容器
首先查看所有容器,包括停止和未停止的
$ docker ps -a
启动一个已经停止的容器
$ docker start b750bbbcfd88 -
守护态运行
在大部分的场景下,我们希望 docker 的服务是在后台运行的,我们可以过 -d 指定容器的运行模式。$ docker run -d ubuntu /bin/sh -c "while true; do echo hello world; sleep 1; done" ce554267d7a4c34eefc92c5517051dc37b918b588736d0823e4c846596b04d83
注:加了 -d 参数默认不会进入容器,想要进入容器需要使用指令 docker exec
4.2 停止容器
- 暂停容器,然后恢复运行
可通过unpause恢复运行$ docker run --name test --rm -it ubuntu bash $ docker pause test $ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 893c811cf845 ubuntu "bash" 2 seconds ago Up 12 seconds (Paused) test
- 终止容器并重新运行
一下是将运行态的容器先终止再重新启动$ docker stop <容器 ID> $ docker start <容器 ID>
$ docker restart <容器 ID>
4.3 进入容器
attach或exec命令
在使用 -d 参数时,容器启动后会进入后台。此时想要进入容器,可以通过以下指令进入:
docker attach
或者
docker exec:推荐大家使用 docker exec 命令,因为此退出容器终端,不会导致容器的停止。
下面演示了使用 docker attach 命令。
$ docker attach 1e560fca3906
注意点:
当我们使用完容器之后进行exit操作,不仅会从容器中退出,还会停止容器的运行。
当多个窗口同时attach 到同一个容器的时候,所有窗口都会同步显示;当某个窗口因命令阻塞时,其他窗口也无法执行操作了。
所以推荐使用exec。
下面演示了使用 exec 命令。
docker exec -it 243c32535da7 /bin/bash
当我们使用完容器之后进行exit操作,使用docker ps可查看到刚才的容器。会从容器退出,但不会停止容器。
4.4 删除容器
默认情况下,docker rm命令只能删除处于终止或退出状态的容器,并不能删除还处于运行状态的容器。
添加-f可以强制删除
$ docker rm -f 1e560fca3906
4.5 导入和导出容器
导出容器 1e560fca3906 快照到本地文件 ubuntu.tar。
$ docker export 1e560fca3906 > ubuntu.tar
导入容器快照
$ cat docker/ubuntu.tar | docker import ubuntu.tar - test/ubuntu:v1
4.6 查看容器
ps、inspect、top、stats子命令
- 查看正在运行的容器
docker ps - 查看某容器的详情
docker container inspect test - 查看某容器的进程
docker top test - 查看某容器的统计信息
查看容器所有信息
haicoder(www.haicoder.net)# docker stats --all
只查看静态信息
haicoder(www.haicoder.net)# docker stats --no-stream
5 访问Docker仓库
仓库是存放镜像的地方,一个仓库可以存放多个镜像。一个registry服务器是具体的服务器用来存放仓库的地方。
5.1 Docker Hub公共镜像仓库
5.2 第三方镜像市场
5.3 搭建本地私有仓库
- 使用registry镜像创建私有仓库
$ docker run -d -p 5000:5000 registry:2
这将自动下载并启动一个registry容器,创建本地的私有仓库服务。
2. 管理私有仓库
6 Docker数据管理
引言:
docker的镜像是由多个只读的文件系统叠加在一起形成的。当我们在我启动一个容器的时候,docker会加载这些只读层并在这些只读层的上面(栈顶)增加一个读写层。这时如果修改正在运行的容器中已有的文件,那么这个文件将会从只读层复制到读写层。该文件的只读版本还在,只是被上面读写层的该文件的副本隐藏。当删除docker,或者重新启动时,之前的更改将会消失。在Docker中,只读层及在顶部的读写层的组合被称为Union File System(联合文件系统)。
为了很好的实现数据保存和数据共享,Docker提出了Volume这个概念,简单的说就是绕过默认的联合文件系统,而以正常的文件或者目录的形式存在于宿主机上。又被称作数据卷。
容器中的管理数据主要有两种方式:
- 数据卷(Volumes)
- 数据容器
6.1 数据卷
为什么使用数据卷?
- 数据持久化
- 数据共享。宿主机和docker的数据是一致的
它完全独立于容器的生存周期,docker不会在容器删除时,删除其挂载的数据卷。
- 创建数据卷
docker volume create mydata - 查看所有数据卷
docker volume ls - 查看数据卷信息
docker volume inspect mydata
注:Mountpoint为数据在本机存储的位置,如果磁盘存储空间不足可修改此位置
挂载:
在用 docker run命令的时候,使用-v标记来创建一个数据卷并挂载到容器里。在一次run中多次使用可以挂载多个数据卷。
docker run -t -i --name datac -v /tmp/webdata1:/webdata1 -v /tmp/webdata2:/webdata2 ubuntu:14.04 /bin/bash
/tmp/webdata1和/tmp/webdata2为创建的宿主机的两个目录,挂载到容器里,一次run可以挂载多个数据卷
6.2 数据卷容器
有一些持续更新的数据需要在容器之间共享,那最好创建数据卷容器。数据卷容器,其实就是一个正常的容器,专门用来提供数据卷供其它容器挂载的。
- 创建一个命名的数据卷容器dbdata
docker create -v /tmp/webdata1 --name dbdata ubuntu:14.04 /bin/true - 创建其他容器来挂载数据卷容器dbdata
在其他容器中使用–volumes-from来挂载dbdata容器中的数据卷。
创建db1容器和db2容器,挂载数据卷容器dbdata:
docker run --volumes-from dbdata --name db1 -i -t ubuntu:14.04 /bin/bash
docker run --volumes-from dbdata --name db2 -i -t ubuntu:14.04 /bin/bash
分别在db1和db2的容器中创建数据,可以看到数据卷容器dbdata中都有这两个容器的数据
6.3 利用数据卷容器备份、恢复、迁移数据
首先使用 --volumes-from 标记来创建一个加载 dbdata 容器卷的容器,并从本地主机挂载当前到容器的 /backup 目录。命令如下:
docker run --volumes-from dbdata -v $(pwd):/backup ubuntu tar cvf /backup/backup.tar /dbdata
容器启动后,使用了 tar 命令来将 dbdata 卷备份为本地的 /backup/backup.tar 。
恢复
如果要恢复数据到一个容器,首先创建一个带有数据卷的容器 dbdata2。
docker run -v /dbdata --name dbdata2 ubuntu /bin/bash
然后创建另一个容器,挂载 dbdata2 的容器,并使用 untar 解压备份文件到挂载的容器卷中。
docker run --volumes-from dbdata2 -v $(pwd):/backup busybox tar xvf /backup/backup.tar
7 端口映射与容器互联
如何实现多个容器之间能够互相访问对方的服务
7.1 端口映射实现容器访问
当容器中运行一些网络应用,要让外部访问这些应用时,可以通过-P或-p 参数来指定端口映射。
当使用-P(大写的)标记时,Docker会随机映射一个49000~49900的端口到内部容器开放的网络端口:
-p(小写),可以指定映射端口
7.2 Docker容器互联
端口映射并不是唯一把 docker 连接到另一个容器的方法。
docker 有一个连接系统允许将多个容器连接在一起,共享连接信息。
docker 连接会创建一个父子关系,其中父容器可以看到子容器的信息。
创建一个新的 web 容器,并将它连接到 db 容器:
docker run -d -P --name web --link db:db training/webapp python app.py
此时,db 容器和 web 容器建立互联关系。
–link参数的格式为–link name:alias,其中name是要链接的容器的名称,alias是别名。
8 DockerFile创建容器
8.1 Dockerfile主体分为四个部分
基础镜像信息、维护者信息、镜像操作指令、容器启动时执行指令
8.2 Dockerfile指令说明
指令主要分为两大类:配置指令和操作指令
8.3 指令介绍
-
FROM和RUN指令
FROM:定制的镜像都是基于的镜像名称,这里的 nginx 就是定制需要的基础镜像。后续的操作都是基于 nginx。
RUN:用于执行后面跟着的命令行命令。有以下两种格式:
方式一:shell 格式:RUN <命令行命令> # <命令行命令> 等同于,在终端操作的 shell 命令。
方式二:exec 格式:
RUN ["可执行文件", "参数1", "参数2"] # 例如:b 成功,会返回最终镜像的ID 例如: # RUN ["./test.php", "dev", "offline"] 等价于 RUN ./test.php dev offlinbe 成功,会返回最终镜像的ID 例如:
注意:Dockerfile 的指令每执行一次都会在 docker 上新建一层。所以过多无意义的层,会造成镜像膨胀过大。例如:
FROM centos RUN yum -y install wget \ && wget -O redis.tar.gz "http://download.redis.io/releases/redis-5.0.3.tar.gz" \ && tar -xvf redis.tar.gz
如上,以 && 符号连接命令,这样执行后,只会创建 1 层镜像。
-
LABEL
LABEL 指令用来给镜像添加一些元数据(metadata),以键值对的形式
如,可以添加作者的信息
LABEL org.opencontainers.image.authors=“runoob” -
ARG与ENV
ENV设置环境变量,定义了环境变量,那么在后续的指令中,就可以使用这个环境变量。
ARG 设置的环境变量仅对 Dockerfile 内有效,也就是说只有 docker build 的过程中有效,构建好的镜像内不存在此环境变量。 -
ADD和COPY指令
ADD和COPY指令类似,当使用本地目录为源目录时,推荐使用COPY指令
ADD
COPY
ADD 的缺点:在不解压的前提下,无法复制 tar 压缩文件。会令镜像构建缓存失效,从而可能会令镜像构建变得比较缓慢。具体是否使用,可以根据是否需要自动解压来决定。 -
CMD和RUN指令
类似于 RUN 指令,用于运行程序,但二者运行的时间点不同:
CMD 在docker run 时运行。
RUN 是在 docker build。
作用:为启动的容器指定默认要运行的程序,程序运行结束,容器也就结束。CMD 指令指定的程序可被 docker run 命令行参数中指定要运行的程序所覆盖。
注意:如果 Dockerfile 中如果存在多个 CMD 指令,仅最后一个生效。
-
ENTRYPOINT和CMD指令
类似于 CMD 指令,但其不会被 docker run 的命令行参数指定的指令所覆盖,而且这些命令行参数会被当作参数送给 ENTRYPOINT 指令指定的程序。 -
EXPOSE
仅仅只是声明端口。
作用:
帮助镜像使用者理解这个镜像服务的守护端口,以方便配置映射。
在运行时使用随机端口映射时,也就是 docker run -P 时,会自动随机映射 EXPOSE 的端口。
格式:
EXPOSE <端口1> [<端口2>…]
8.4 创建镜像
使用docker build来创建镜像
Docker服务端在校验Dockerfile格式通过后,逐条执行其中定义的指令,碰到ADD、COPY和RUN指令会生成一层新的镜像。最终如果创建镜像成功,会返回最终镜像的ID
例如:
[root@localhost soft]# docker build -t centos:base -f /soft/docker/Dockerfile /soft
注意:通过-f来指定Dockerfile文件的位置,后面的/soft及其目录下必须能够找到Dockerfile文件否则就会报上下文环境的错误,MV,COPY,ADD的文件位置都是相对/soft来说的。
–tag, -t,镜像的名字及tag,通常name:tag或者name格式;可以在一次构建中为一个镜像设置多个tag
9 为镜像添加ssh服务
如何远程访问容器?
创建带有ssh服务的镜像:
两种方式,1:基于docker commit命令, 2:基于Dockerfile创建
9.1 基于docker commit命令
- 正常拉取镜像创建容器
- 运行容器的时候进入到容器中安装和配置ssh服务
- 生成公钥到authorized_keys文件中
- 编写ssh服务自动启动的run.sh中
- commit保存为一个新的sshd:ubuntu镜像
- 下次使用镜像的时候添加端口映射就可以使用ssh登陆到容器了
9.2 基于Dockerfile创建
- 创建Dockerfile文件和run.sh
- 编写run.sh,在宿主机生成密钥对到authorized_keys中
- 编写Dockerfile文件配置ssh服务
- 创建镜像、执行并测试镜像
总结:Docker理念是一个容器只运行一个服务,每个容器启动都增加一个额外的ssh服务,应用容器应该保持原有的生命周期,系统容器应该支持ssh,便于管理员的登陆。
10 Docker Compose:Docker管理工具
Docker Compose是一个用来定义和运行复杂应用的Docker工具。一个使用Docker容器的应用,通常由多个容器组成。使用Docker Compose不再需要使用shell脚本来启动容器,而使用服务编排的方式来管理容器。
Docker Compose 通过一个配置文件来管理多个Docker容器,在配置文件中,所有的容器通过services来定义,然后使用docker-compose脚本来启动,停止和重启应用,和应用中的服务以及所有依赖服务的容器,非常适合组合使用多个容器进行开发的场景。Docker Compose 的前身是 Fig。Fig 是一个由 Orchard 公司开发的强有力的工具,在当时是进行多容器管理的最佳方案。
Fig 是一个基于 Docker 的 Python 工具,允许用户基于一个 YAML 文件定义多容器应用,从而可以使用 fig 命令行工具进行应用的部署。Fig 还可以对应用的全生命周期进行管理。
11 研发人员看待docker
- Docker可以快速部署安装开发测试环境
- 方便部署各类服务
12 Docker Machine
在本地或云环境搭建一套Docker主机集群
13 Docker Compose
Compose 是用于定义和运行多容器 Docker 应用程序的工具。
通过 Compose,您可以使用 YML 文件来配置应用程序需要的所有服务。然后,使用一个命令,就可以从 YML 文件配置中创建并启动所有服务。
13.1 使用Compose的三个步骤
- 使用 dockerfile 定义应用程序的环境。
- 使用 docker-compose.yml 定义构成应用程序的服务,这样它们可以在隔离环境中一起运行。
- 执行 docker-compose up 命令来启动并运行整个应用程序。
13.2 Compose的yaml文件编写
version: "3"
services:
webapp:
image: examples/web
ports:
- "80:80"
volumes:
- "/data"
所有的服务都在services根目录下面,里面是服务器容器的配置信息
一些感想:
- dockerfile和run.sh是一般是成对出现的,dockerfile用来构建镜像,run.sh用来启动服务