一、Docker概述
1、Docker是什么
Docker 是一个开源的应用容器引擎 ,基于 Go 语言 并遵从 Apache2.0 协议开源;
Docker 可以让开发者打包他们的应用以及依赖包到一个轻量级 、可移植的容器中,然后发布到任何流行的 Linux 机器上,也可以实现虚拟化 ;
容器是完全使用沙箱机制 ,相互之间不会有任何接口,更重要的是容器性能开销极低;
Docker 从 17.03 版本之后分为 CE(Community Edition-社区版)和 EE(Enterprise Edition-企业版)。
Docker是一个Client-Server结构 的系统,以守护进程运行在主机上。通过Socket 从客户端进行访问。
Docker 是 PaaS 提供商 dotCloud 开源的一个基于 LXC 的高级容器引擎,源代码托管在 Github 上
2、Docker应用场景
Web应用的自动化打包和发布,自动化测试和持续集成、发布;
在服务型环境中部署和调整数据库或其他的后台应用;
从头编译或者扩展现有的 OpenShift 或 Cloud Foundry 平台来搭建自己的 PaaS 环境。
3、Docker资源
4、Docker的优点
传统虚拟机与Docker对比:
虚拟机的缺点:
Docker的特点:
不模拟完整的操作系统,系统内核(kernel)非常小,更少的抽象层(GuestOS:如Centos)
容器内的应用直接运行在宿主机的内核,容器本身没有自己的内核 ,也没有虚拟硬件 。
每个容器相互隔离 ,内部都有属于自己的文件系统,互不影响。
5、Docker实现DevOps(开发、运维)
应用更快速的交付和部署
打包镜像发布测试,一键运行;不再需要写大量帮助文档,安装程序
更便捷的升级和扩缩容?
部署应用就和搭积木一样
更简单的系统运维
开发和测试的环境高度一致
更高效的计算资源利用
内核级别的虚拟化,可以在一个物理机上运行很多的容器实例,服务器性能可以被压榨到极致。
6、Docker基本组成
镜像(image):镜像是一种轻量级、可执行的独立软件包,用来打包软件运行环境和基于运行环境开发的软件。它包含运行某个软件所需的所有内容,包括代码、运行时、库、环境变量和配置文件。相当于一个模板,通过这个模板来创建容器服务,可以通过一个镜像创建多个容器。
容器(container):独立运行一个或一组应用。基本命令有:启动,停止,删除等。可理解为一个简单的linux系统。
仓库(repository):存放镜像的地方(公有/私有)
7、Docker为什么比VM快
docker有着比虚拟机更少的抽象层。由于docker不需要Hypervisor实现硬件资源虚拟化,运行在docker容器上的程序直接使用的都是实际物理机的硬件资源。因此在CPU、内存利用率上docker将会在效率上有明显优势。
docker利用的是宿主机的内核,而不需要Guest OS。
GuestOS: VM(虚拟机)里的的系统(OS)
HostOS:物理机里的系统(OS)
因此,当新建一个 容器时,docker不需要和虚拟机一样重新加载一个操作系统内核。然而避免引导、加载操作系统内核是个比较费时费资源的过程,当新建一个虚拟机时,虚拟机软件需要加载GuestOS,返个新建过程是分钟级别的。而docker由于直接利用宿主机的操作系统,则省略了这个复杂的过程,因此新建一个docker容器只需要几秒钟。
二、Docker安装
1、安装
Docker官方安装文档:https://docs.docker.com/engine/install/
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 uname -r # 内核要求3.0以上# 1.卸载旧版本 yum remove docker \ docker-client \ docker-client-latest \ docker-common \ docker-latest \ docker-latest-logrotate \ docker-logrotate \ docker-engine# 2.需要的安装包 yum install -y yum-utils# 3.设置镜像的仓库 yum-config-manager \ --add-repo \ https://download.docker.com/linux/centos/docker-ce.repo# 默认是从国外的,不推荐 # 推荐使用国内的 yum-config-manager \ --add-repo \ https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo# 更新yum软件包索引 yum makecache fast# 4.安装docker相关的 docker-ce 社区版 而ee是企业版 yum install docker-ce docker-ce-cli containerd.io# 5、启动docker systemctl start docker# 6. 使用docker version查看是否安装成功 docker version# 7. 测试 docker run hello-world
2、卸载
1 2 3 4 5 # 1. 卸载依赖 yum remove docker-ce docker-ce-cli containerd.io# 2. 删除资源 rm -rf /var/lib/docker# /var/lib/docker 是docker的默认工作路径!
3、镜像加速配置
参考:https://www.runoob.com/docker/docker-mirror-acceleration.html
三、Docker命令
Docker命令的详细使用方法请参考 官网 或者 docker --help 进行查询,这里只记录部分常用命令。
pull
从镜像仓库中拉取或者更新指定镜像,在未声明镜像标签时,默认标签为latest。
1 2 3 4 Usage: docker pull [OPTIONS] NAME[:TAG|@DIGEST] Options: -a 拉取某个镜像的所有版本 --disable-content-trust 跳过校验,默认开启
run
创建并启动一个容器
常见的坑,docker容器使用后台运行,就必须要有要一个前台进程,docker发现没有应用,就会自动停止!
容器运行的命令如果不是那些一直挂起的命令 (比如运行top,tail) ,就是会自动退出的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 Usage: docker run [OPTIONS] IMAGE [COMMAND] [ARG...] Options: -d, --detach 后台运行容器,并输出容器ID -e, --env list 设置环境变量,该变量可以在容器内使用 -h, --hostname string 指定容器的hostname -i, --interactive 以交互模式运行容器,通常与-t同时使用 -l, --label list 给容器添加标签 --name string 设置容器名称,否则会自动命名 --network string 将容器加入指定网络 -p, --publish list 设置容器映射端口 -p ip:主机端口:容器端口 -p 主机端口:容器端口(常用) -p 容器端口 -P,--publish-all 将容器设置的所有exposed端口进行随机映射 --restart string 容器重启策略,默认为不重启 on-failure[:max-retries]:在容器非正常退出时重启,可以设置重启次数。 unless-stopped:总是重启,除非使用stop停止容器 always:总是重启 --rm 容器退出时则自动删除容器 -t, --tty 分配一个伪终端 -u, --user string 运行用户或者UID -v, --volume list 数据挂载 -w, --workdir string 容器的工作目录 --privileged 给容器特权
build
通过 Dockerfile 构建镜像
1 2 3 4 5 Usage: docker build [OPTIONS] PATH | URL | - Options: -f, --file string 指定Dockerfile,默认为当前路径的Dockerfile -q, --quiet 安静模式,构建成功后输出镜像ID -t, --tag list 给镜像设置tag,name:tag
commit
通过容器创建一个新镜像,提交当前容器为新的镜像
1 2 3 4 Usage: docker commit [OPTIONS] CONTAINER [REPOSITORY[:TAG]] Options: -a, --author string 作者 -m, --message string 提交信息
cp
在容器和宿主机之间拷贝文件
1 2 3 4 5 Usage: docker cp [OPTIONS] CONTAINER:SRC_PATH DEST_PATH docker cp [OPTIONS] SRC_PATH CONTAINER:DEST_PATH Options: -a, --archive 保留文件权限
exec
向正在运行的容器下发命令
1 2 3 4 5 6 7 8 Usage: docker exec [OPTIONS] CONTAINER COMMAND [ARG...] Options: -d, --detach 在后台运行命令 -e, --env list 设置环境变量 -i, --interactive 以交互模式运行 -t, --tty 分配一个伪终端 -u, --user string 执行命令的用户 -w, --workdir string 工作目录
export
将容器导出为一个tar包
1 2 3 Usage: docker export [OPTIONS] CONTAINER Options: -o, --output string tar包名称
images
列出镜像
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 Usage: docker images [OPTIONS] [REPOSITORY[:TAG]] Options: -a, --all 显示所有镜像 -f, --filter filter 使用过滤器过滤镜像 dangling true or false , true 列出没有标签的,false 相反 label (label=<key> or label=<key>=<value>),如果镜像设置有label,则可以通过label过 滤 before (<image-name>[:<tag>], <image id> or <image@digest>) - 某个镜像前的镜像 since (<image-name>[:<tag>], <image id> or <image@digest>) - 某个镜像后的镜像 reference (pattern of an image reference) - 模糊查询,例:-- filter=reference='busy*:*libc' --format string 格式化输出 .ID 镜像ID .Repository 镜像仓库 .Tag 镜像tag .Digest Image digest .CreatedSince 创建了多久 .CreatedAt 镜像创建时间 .Size 镜像大小 -q, --quiet 只显示镜像ID --digests 显示镜像的摘要信息 --no-trunc 显示完整的镜像信息
import
通过导入tar包的方式创建镜像
1 2 3 Usage: docker import [OPTIONS] file|URL|- [REPOSITORY[:TAG]] Options: -m, --message string 设置提交信息
kill
杀死一个或多个容器
1 Usage: docker kill [OPTIONS] CONTAINER [CONTAINER...]
load
从tar包加载一个镜像
1 2 3 4 Usage: docker load [OPTIONS] Options: -i, --input string 指定tar包 -q, --quiet 只显示ID
login
登录Docker镜像仓库
1 2 3 4 Usage: docker login [OPTIONS] [SERVER] Options: -p, --password string 密码 -u, --username string 账户
logout
退出Docker镜像仓库
1 Usage: docker logout [SERVER]
logs
显示容器日志
1 2 3 4 5 6 7 8 9 10 11 12 Usage: docker logs [OPTIONS] CONTAINER Options: --details 显示详细日志 -f, --follow 跟随日志输出 --tail string 显示行数 -t, --timestamps 显示时间戳 显示日志 -tf 显示日志信息(一直更新) --tail number 需要显示日志条数 docker logs -t --tail n 容器id 查看n行日志 docker logs -ft 容器id 动态更新日志
ps
列出容器
1 2 3 4 5 6 7 8 9 10 11 12 Usage: docker ps [OPTIONS] Options: -a, --all 列出所有容器 -f, --filter filter 使用过滤器过滤 --format string 格式化输出 -n, --last int 显示最后创建的n个容器 -l, --latest 显示最后一个创建的容器 -q, --quiet 只显示容器ID -s, --size 显示大小 --no-trunc :不截断输出。 docker ps -aq 列出全部镜像id
push
将容器推送到镜像仓库
1 Usage: docker push [OPTIONS] NAME[:TAG]
rename
给容器重命名
1 Usage: docker rename CONTAINER NEW_NAME
restart
重启一个或多个容器
1 Usage: docker restart [OPTIONS] CONTAINER [CONTAINER...]
rm
删除一个或多个容器
1 2 3 4 5 6 7 8 9 10 Usage: docker rm [OPTIONS] CONTAINER [CONTAINER...] Options: -f, --force 强制删除 -v, --volumes 同时删除数据卷 docker rm 容器名/id 删除指定容器 docker rm &(docker ps -aq) 删除全部容器 docker rm -f $(docker ps -aq) 强制删除全部容器 docker ps -a -q|xargs docker rm 删除所有的容器
rmi
删除一个或多个镜像
1 2 3 4 5 6 7 Usage: docker rmi [OPTIONS] IMAGE [IMAGE...] Options: -f, --force 强制删除 docker rmi -f 镜像id 删除指定的镜像 docker rmi -f 镜像id 镜像id 镜像id 镜像id 删除指定的镜像 docker rmi -f $(docker images -aq) 删除全部的镜像
save
将一个或多个镜像保存为tar包
1 2 3 Usage: docker save [OPTIONS] IMAGE [IMAGE...] Options: -o, --output string tar包名称
search
查找镜像
1 2 3 4 Usage: docker search [OPTIONS] TERM --no-trun 显示完整的镜像描述 -s 列出收藏数不小于指定值的镜像 --automated 只列出 automated build类型的镜像
start
启动一个或多个容器
1 Usage: docker start [OPTIONS] CONTAINER [CONTAINER...]
stats
显示容器资源使用情况
1 2 3 Usage: docker stats [OPTIONS] [CONTAINER...] Options: -a, --all 显示所有容器,默认只显示正在运行的容器
stop
停止一个或多个容器
1 Usage: docker stop [OPTIONS] CONTAINER [CONTAINER...]
tag
给镜像设置新的tag
1 Usage: docker tag SOURCE_IMAGE[:TAG] TARGET_IMAGE[:TAG]
inspect
获取容器或镜像的元数据
1 2 3 4 5 6 7 8 9 10 11 12 Usage: docker inspect [OPTIONS] NAME|ID [NAME|ID...] docker inspect 55321bcae33d [ { "Id" : "55321bcae33d15da8280bcac1d2bc1141d213bcc8f8e792edfd832ff61ae5066" , "Created" : "2020-05-15T05:22:05.515909071Z" , "Path" : "/bin/sh" , ... } ]
其他命令
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 docker version #显示docker的版本信息。 docker info #显示docker的系统信息,包括镜像和容器的数量 docker 命令 --help #帮助命令 #帮助文档的地址:https://docs.docker.com/engine/reference/commandline/build/ Exit # 从容器中退回主机 CTRL+Q+P # 容器不停止退出 docker ps # 显示当前运行的容器 -a # 带出历史运行过的容器 docker exec 容器名/id #进入当前容器后开启一个新的终端,可以在里面操作。(常用) docker attach 容器名/id # 进入容器正在执行的终端 docker top 容器id # 查看容器中进程信息 docker history 镜像名 # 查看镜像变更历史
命令总结
四、Docker可视化
Portainer:
Docker图形化界面管理工具!提供一个后台面板供我们操作!
1 2 docker run -d -p 8080:9000 \ --restart=always -v /var/run/docker.sock:/var/run/docker.sock --privileged=true portainer/portainer
**Rancher:**后面再用!
五、Docker镜像详解
1、UnionFS(联合文件系统)
联合文件系统(UnionFS)是一种分层、轻量级并且高性能的文件系统,它支持对文件系统的修改作为一次提交来一层层的叠加,同时可以将不同目录挂载到同一个虚拟文件系统下。联合文件系统是 Docker 镜像的基础。镜像可以通过分层来进行继承,基于基础镜像(没有父镜像),可以制作各种具体的应用镜像。
特性:一次同时加载多个文件系统,但从外面看起来只能看到一个文件系统。联合加载会把各层文件系统叠加起来,这样最终的文件系统会包含所有底层的文件和目录。
2、镜像加载原理
Docker的镜像实际由一层一层的文件系统组成:
bootfs(boot file system)主要包含bootloader和kernel。bootloader主要是引导加载kernel,完成后整个内核就都在内存中了。此时内存的使用权已由bootfs转交给内核,系统卸载bootfs。可以被不同的Linux发行版公用。
rootfs(root file system)包含典型Linux系统中的/dev,/proc,/bin,/etc等标准目录和文件。rootfs就是各种不同操作系统发行版(Ubuntu,Centos等)。因为底层直接用Host的kernel,rootfs只包含最基本的命令,工具和程序就可以了。
分层理解:所有的Docker镜像都起始于一个基础镜像层,当进行修改或增加新的内容时,就会在当前镜像层之上,创建新的容器层。容器在启动时会在镜像最外层上建立一层可读写的容器层(R/W),而镜像层是只读的(R/O)。
创建新的分层提交为新镜像:
1 docker commit -m="描述信息" -a="作者" 容器id 目标镜像名:[tag] # 编辑容器后提交容器成为一个新镜像
为什么Docker镜像要采用这种分层的结构呢?
最大的好处,我觉得莫过于资源共享 了!比如有多个镜像都从相同的Base镜像构建而来,那么宿主机只需在磁盘上保留一份base镜像,同时内存中也只需要加载一份base镜像,这样就可以为所有的容器服务了,而且镜像的每一层都可以被共享。
查看镜像分层的方式可以通过docker image inspect 镜像名
命令:
1 2 3 4 5 6 7 8 9 10 11 "RootFS": { "Type": "layers", "Layers": [ "sha256:c2adabaecedbda0af72b153c6499a0555f3a769d52370469d8f6bd6328af9b13", "sha256:744315296a49be711c312dfa1b3a80516116f78c437367ff0bc678da1123e990", "sha256:379ef5d5cb402a5538413d7285b21aa58a560882d15f1f553f7868dc4b66afa8", "sha256:d00fd460effb7b066760f97447c071492d471c5176d05b8af1751806a1f905f8", "sha256:4d0c196331523cfed7bf5bafd616ecb3855256838d850b6f3d5fba911f6c4123", "sha256:98b4a6242af2536383425ba2d6de033a510e049d9ca07ff501b95052da76e894" ] },
Docker通过存储引擎(新版本采用快照机制)的方式来实现镜像层堆栈,并保证多镜像层对外展示为统一的文件系统。
Linux上可用的存储引撃 有AUFS、 Overlay2、 Device Mapper、Btrfs以及ZFS。顾名思义,每种存储引擎都基于 Linux中对应的件系统或者块设备技术,井且每种存储引擎都有其独有的性能特点。
Docker在 Windows上仅支持 windowsfilter 一种存储引擎,该引擎基于NTFS文件系统之上实现了分层和CoW [1]。
3、Commit镜像
如果你想要保存当前容器的状态,就可以通过commit来提交,获得一个镜像,就好比我们我们使用虚拟机的快照。
1 2 3 4 5 6 7 8 9 10 11 12 docker commit 提交容器成为一个新的副本# 命令和git原理类似 docker commit -m="描述信息" -a="作者" 容器id 目标镜像名:[TAG]# 1、启动一个默认的tomcat docker run -d -p 8080:8080 tomcat# 2、发现这个默认的tomcat 是没有webapps应用,官方的镜像默认webapps下面是没有文件的! docker exec -it 容器id# 3、拷贝文件进去 # 4、将操作过的容器通过commit提交为一个镜像!我们以后就使用我们修改过的镜像即可,这就是我们自己的一个修改的镜像。 docker commit -m="描述信息" -a="作者" 容器id 目标镜像名:[TAG] docker commit -a="itnxd" -m="add webapps app" 容器id tomcat02:1.0
六、容器数据卷
1、什么是容器数据卷
为了实现数据持久化,使容器之间可以共享数据。可以将容器内的目录,挂载到宿主机上或其他容器内,实现同步和共享的操作。即使将容器删除,挂载到本地的数据卷也不会丢失。
卷 就是目录或文件,存在于一个或多个容器中,由docker 挂载到容器,但不属于联合文件系统,因此能够绕过Union FileSystem提供一些用于持续存储或共享数据的特性。
卷的设计目的就是数据的持久化,完全独立于容器的生存周期,因此Docker不 会在容器删除时删除其挂载的数据卷
特点:
数据卷可在容器之间共享或重用数据
卷中的更改可以直接生效
数据卷中的更改不会包含在镜像的更新中
数据卷的生命周期一直持续到没有容器使用它为止
容器的持久化
容器间继承+共享数据
2、使用容器数据卷
挂载使用-v命令:
1 dokcer run -it -v 主机内目录:容器内目录 镜像名/id
将容器内目录挂载到主机内目录上,通过docker inspect 命令查看该容器即可以看到挂载信息:
可在Dockerfile中使用VOLUME指令来给镜像添加一个或多个数据卷:
3、匿名挂载
命令:
1 docker run -d -v 容器内目录 镜像名/id # 匿名挂载
匿名挂载后,使用docker volume ls 命令查看所有挂载的卷:
每一个VOLUME NAME对应一个挂载的卷,由于挂载时未指定主机目录,因此无法直接找到目录,他有一个默认目录:在 /var/lib/docker/volumes/xxxx/_data
下,xxx表示VOLUME NAME的字符串!
4、具名挂载
命令:
1 docker run -d -v 卷名:容器内目录 镜像名/id # 具名挂载
可以发现挂载的卷:volume01,并通过docker volume inspect 卷名 命令找到主机内目录:同样是在默认的/var/lib/docker/volumes/
下:
所有docker容器内的卷,在未指定主机内目录时,都在:/var/lib/docker/volumes/卷名/_data
下,可通过具名挂载可以方便的找到卷,因此广泛使用这种方式进行挂载。
5、MySQL安装
1 2 3 4 5 # 获取mysql镜像 docker pull mysql:5.7# 运行容器,需要做数据挂载,安装启动mysql,需要配置密码的,这是要注意点! # 参考官网hub docker run -d -p 3306:3306 -v /home/mysql/conf:/etc/mysql/conf.d -v /home/mysql/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 --name mysql01 mysql:5.7
6、容器数据共享
--volumes-from
:容器间共享挂载目录
1 2 3 4 docker run -d -p 3306:3306 -v /home/mysql/conf:/etc/mysql/conf.d -v /home/mysql/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 --name mysql01 mysql:5.7 docker run -d -p 3307:3306 -e MYSQL_ROOT_PASSWORD=123456 --name mysql02 --volumes-from mysql01 mysql:5.7# 这个时候,可以实现两个容器数据同步!
7、小结
1 2 3 4 # 三种挂载: 匿名挂载、具名挂载、指定路径挂载 -v 容器内路径 #匿名挂载 -v 卷名:容器内路径 #具名挂载 -v /宿主机路径:容器内路径 #指定路径挂载 docker volume ls 是查看不到的
所有的docker容器内的卷,没有指定目录的情况下都是在 /var/lib/docker/volumes/xxxx/_data
下
如果指定了目录,docker volume ls
是查看不到的。
容器之间的配置信息的传递,数据卷容器的生命周期一直持续到没有容器使用为止。但是一旦你持久化到了本地,这个时候,本地的数据是不会删除的!
拓展:
1 2 3 4 5 6 7 # 通过 -v 容器内路径: ro rw 改变读写权限 ro #readonly 只读 rw #readwrite 可读可写 docker run -d -P --name nginx05 -v juming:/etc/nginx:ro nginx docker run -d -P --name nginx05 -v juming:/etc/nginx:rw nginx# ro 只要看到ro就说明这个路径只能通过宿主机来操作,容器内部是无法操作!
七、Dockerfile
Dockerfile是用来构建docker镜像的文件!
1、构建步骤
1、编写一个dockerfile文件,随后运行命令
1 2 3 docker build -f 文件路径 -t 标签 . # 文件名为Dockerfile时可省略-f docker run # 运行镜像 docker push # 发布镜像
2、Dockerfile命令
命令
效果
FROM
基础镜像:Centos/Ubuntu
MAINTAINER
镜像作者+邮箱
RUN
镜像构建的时候需要运行的命令
ADD
为镜像添加内容(压缩包)(Copy + 解压缩 )
WORKDIR
镜像工作目录(进入容器时的目录)
VOLUME
挂载的目录
EXPOSE
映射端口配置
CMD/ENTRYPOINT
指定这个容器启动时要运行的命令(CMD替代先前命令,ENTRYPOINT在先前命令后追加)
COPY
类似于ADD,将文件拷贝到镜像中,COPY src desc 或 COPY[“src”, “desc”]
ENV
构建时设置环境变量
3、注意事项
每个保留关键字(指令)都必须是大写字母
从上到下顺序执行
“#” 表示注释
每一个指令都会创建提交一个新的镜像层并提交
2、CMD和ENTRYPOINT
区别测试:
CMD:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 # Dockerfile文件: FROM centos CMD ["ls","-a"]# 构建镜像 $ docker build -f dockerfile-test-cmd -t cmd-test:0.1 . # 运行镜像 $ docker run cmd-test:0.1 . .. .dockerenv bin dev# 想追加一个命令 -l 成为ls -al # cmd的情况下 -l 替换了CMD["ls" ,"-l" ]。 -l 不是命令所有报错 $ docker run cmd-test:0.1 -l docker: Error response from daemon: OCI runtime create failed: container_linux.go:349: starting container process caused "exec: \"-l\":executable file not found in $PATH": unknown. ERRO[0000] error waiting for container: context canceled
ENTRYPOINT:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 # Dockerfile文件 FROM centos ENTRYPOINT ["ls","-a"]$ docker run entrypoint-test:0.1 . .. .dockerenv bin dev etc ...# 我们的命令,是直接拼接在我们得ENTRYPOINT命令后面的 $ docker run entrypoint-test:0.1 -l total 56 drwxr-xr-x 1 root root 4096 May 16 06:32 . drwxr-xr-x 1 root root 4096 May 16 06:32 .. -rwxr-xr-x 1 root root 0 May 16 06:32 .dockerenv
3、案例
独特的Centos:
vim mydockerfile-centos:
1 2 3 4 5 6 7 8 9 10 FROM centosMAINTAINER xxx<xxx@qq.com>ENV MYPATH /usr/localWORKDIR $MYPATH RUN yum -y install vim RUN yum -y install net-tools EXPOSE 80 CMD echo $MYPATH CMD echo "-----end----" CMD /bin/bash
1 docker build -f mydockerfile-centos -t mycentos:0.1 .
独特的Tomcat:
1 2 3 4 5 6 7 8 9 10 11 12 13 FROM centos MAINTAINER xxx<xxx@qq.com>COPY README /usr/local /README ADD jdk-8u231-linux-x64.tar.gz /usr/local / ADD apache-tomcat-9.0.35.tar.gz /usr/local / RUN yum -y install vim ENV MYPATH /usr/local WORKDIR $MYPATH ENV JAVA_HOME /usr/local/jdk1.8.0 _231 ENV CATALINA_HOME /usr/local/apache-tomcat-9.0 .35 ENV PATH $PATH:$JAVA_HOME/bin:$CATALINA_HOME/lib EXPOSE 8080 CMD /usr/local /apache-tomcat-9.0.35/bin/startup.sh && tail -F /usr/local /apachetomcat-9.0.35/logs/catalina.out
1 2 3 4 # 因为dockerfile命名使用默认命名 因此不用使用-f 指定文件 $ docker build -t mytomcat:0.1 . $ docker run -d -p 8080:8080 --name tomcat01 -v /home/www/build/tomcat/test :/usr/local /apache-tomcat-9.0.35/webapps/test -v /home/www/build/tomcat/logs/:/usr/local /apache-tomcat-9.0.35/logs mytomcat:0.1
4、发布镜像到DockerHub
1、使用docker login登录账号
1 2 3 4 5 6 7 8 9 10 11 [root@VM-8-2-centos ~]# docker login --help Usage: docker login [OPTIONS] [SERVER] Log in to a Docker registry. If no server is specified, the default is defined by the daemon. Options: -p, --password string Password --password-stdin Take the password from stdin -u, --username string Username
2、使用docker push到远程仓库
1 2 3 4 5 6 7 # 会发现push不上去,因为如果没有前缀的话默认是push到 官方的library # 解决方法 # 第一种 build的时候添加你的dockerhub用户名,然后在push就可以放到自己的仓库了 $ docker build -t itnxd/mytomcat:0.1 . # 第二种 使用docker tag $ docker tag 容器id itnxd/mytomcat:1.0 $ docker push itnxd/mytomcat:1.0
八、Docker网络
1、Docker0
通过命令ip addr 查看本地ip地址,我们发现除了本机回环地址和的内网地址外,还多了一个网卡:Docker0,这是Docker服务启动后自动生成的。
而如果启动正在后台运行的tomcat容器,同样使用ip addr 命令,发现容器得到了一个新的网络:12: eth@if13 ,ip地址:172.17.0.2 。这是Docker在容器启动时为其分配的。
我们惊奇地发现了一个新网络13: vethda1df4b@if12 ,对应容器内网络地址的12: eth@if13 。
linux可以ping通docker容器内部,因为docker0的ip地址为172.17.0.1 ,容器为172.17.0.2 。在一个网段中!
原理:我们每启动一个docker容器,docker就会给容器分配一个默认的可用ip,我们只要安装了docker,就会有一个网卡docker0(bridge)。网卡采用桥接模式,并使用veth-pair技术(veth-pair就是一堆虚拟设备接口,成对出现,一段连着协议,一段彼此相连,充当一个桥梁。)。
docker中的所有网络接口都是虚拟的 ,转发效率高。删除容器后,对应的网桥也随之删除。
所有的容器不指定网络的情况下,都是docker0路由的,docker会给我们的容器分配一个默认的可用ip。
2、–link
若编写一个微服务并连接数据库,如果数据库ip改变,如何根据容器名而不是ip访问容器?显然,直接使用容器名是无法ping通容器内部的!
这时我们可以在容器启动命令中加入一个选项:–link ,使得我们可以根据容器名来访问容器。
1 docker run -d -P --link 容器名/id 镜像名/id
然而反向就不可以ping通,这是因为–link的本质是把需要连接的容器名/id写入启动容器的Hosts文件中,即增加了一个ip和容器名/id的映射:
目前已经不建议使用这种方式。
3、自定义网络
使用如下命令查看docker的网络类型:
1 docker network ls # 查看所有的docker网络
bridge:桥接(docker默认)
none:不配置网络
host:和宿主机共享网络
创建一个新的网络:
1 docker network create --driver 网络模式 --subnet 子网ip --gateway 网关 网络名
使用docker network inspect命令查看其详细信息:
只要多个容器启动时都通过 –net ,选用了同一个已创建的网络,不同容器间即可通过ip地址或容器名/id连通,因为都在一个网段内!
4、网络联通
对于建立在不同网络下(docker0, newnet)的两个容器tomcat01和tomcat02,他们的网段不同,因此是无法彼此ping通容器内部的:
这时我们需要通过docker network connect 命令打通容器与网络之间的连接:
1 docker network connect 网络名 容器名/id
原理 :将一个容器赋予多个ip地址,同样可以用docker network inspect 命令查看网络连通后,该网络的变化:
新建的网络中绑定了一个新的容器!此时
九、Docker案例
1、基于Docker的Redis集群搭建
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 # 创建网卡 docker network create redis --subnet 172.38.0.0/16 # 通过脚本创建六个redis配置 for port in $(seq 1 6); \ do \ mkdir -p /mydata/redis/node-${port}/conf touch /mydata/redis/node-${port}/conf/redis.conf cat << EOF >/mydata/redis/node-${port}/conf/redis.conf port 6379 bind 0.0.0.0 cluster-enabled yes cluster-config-file nodes.conf cluster-node-timeout 5000 cluster-announce-ip 172.38.0.1${port} cluster-announce-port 6379 cluster-announce-bus-port 16379 appendonly yes EOF done# 创建结点1 docker run -p 6371:6379 -p 16371:16379 --name redis-1 \ -v /mydata/redis/node-1/data:/data \ -v /mydata/redis/node-1/conf/redis.conf:/etc/redis/redis.conf \ -d --net redis --ip 172.38.0.11 redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf # 创建结点2 docker run -p 6372:6379 -p 16372:16379 --name redis-2 \ -v /mydata/redis/node-2/data:/data \ -v /mydata/redis/node-2/conf/redis.conf:/etc/redis/redis.conf \ -d --net redis --ip 172.38.0.12 redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf# 创建结点3 docker run -p 6373:6379 -p 16373:16379 --name redis-3 \ -v /mydata/redis/node-3/data:/data \ -v /mydata/redis/node-3/conf/redis.conf:/etc/redis/redis.conf \ -d --net redis --ip 172.38.0.13 redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf# 创建结点4 docker run -p 6374:6379 -p 16374:16379 --name redis-4 \ -v /mydata/redis/node-4/data:/data \ -v /mydata/redis/node-4/conf/redis.conf:/etc/redis/redis.conf \ -d --net redis --ip 172.38.0.14 redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf# 创建结点5 docker run -p 6375:6379 -p 16375:16379 --name redis-5 \ -v /mydata/redis/node-5/data:/data \ -v /mydata/redis/node-5/conf/redis.conf:/etc/redis/redis.conf \ -d --net redis --ip 172.38.0.15 redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf# 创建结点6 docker run -p 6376:6379 -p 16376:16379 --name redis-6 \ -v /mydata/redis/node-6/data:/data \ -v /mydata/redis/node-6/conf/redis.conf:/etc/redis/redis.conf \ -d --net redis --ip 172.38.0.16 redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf # 创建集群 docker exec -it redis-1 /bin/sh /data # ls appendonly.aof nodes.conf /data # redis-cli --cluster create 172.38.0.11:6379 172.38.0.12:6379 172.38.0.13:6379 172.38.0.14:6379 172.38.0.15:6379 172.38.0.16:6379 --cluster-replicas 1> >> Performing hash slots allocation on 6 nodes... Master[0] -> Slots 0 - 5460 Master[1] -> Slots 5461 - 10922 Master[2] -> Slots 10923 - 16383 Adding replica 172.38.0.15:6379 to 172.38.0.11:6379 Adding replica 172.38.0.16:6379 to 172.38.0.12:6379 Adding replica 172.38.0.14:6379 to 172.38.0.13:6379 M: 541b7d237b641ac2ffc94d17c6ab96b18b26a638 172.38.0.11:6379 slots:[0-5460] (5461 slots) master M: a89c1f1245b264e4a402a3cf99766bcb6138dbca 172.38.0.12:6379 slots:[5461-10922] (5462 slots) master M: 259e804d6df74e67a72e4206d7db691a300c775e 172.38.0.13:6379 slots:[10923-16383] (5461 slots) master S: 9b19170eea3ea1b92c58ad18c0b5522633a9e271 172.38.0.14:6379 replicates 259e804d6df74e67a72e4206d7db691a300c775e S: 061a9d38f22910aaf0ba1dbd21bf1d8f57bcb7d5 172.38.0.15:6379 replicates 541b7d237b641ac2ffc94d17c6ab96b18b26a638 S: 7a16b9bbb0615ec95fc978fa62fc054df60536f0 172.38.0.16:6379 replicates a89c1f1245b264e4a402a3cf99766bcb6138dbca Can I set the above configuration? (type 'yes' to accept): yes> >> Nodes configuration updated > >> Assign a different config epoch to each node > >> Sending CLUSTER MEET messages to join the cluster Waiting for the cluster to join ...> >> Performing Cluster Check (using node 172.38.0.11:6379) M: 541b7d237b641ac2ffc94d17c6ab96b18b26a638 172.38.0.11:6379 slots:[0-5460] (5461 slots) master 1 additional replica(s) M: a89c1f1245b264e4a402a3cf99766bcb6138dbca 172.38.0.12:6379 slots:[5461-10922] (5462 slots) master 1 additional replica(s) S: 7a16b9bbb0615ec95fc978fa62fc054df60536f0 172.38.0.16:6379 slots: (0 slots) slave replicates a89c1f1245b264e4a402a3cf99766bcb6138dbca S: 061a9d38f22910aaf0ba1dbd21bf1d8f57bcb7d5 172.38.0.15:6379 slots: (0 slots) slave replicates 541b7d237b641ac2ffc94d17c6ab96b18b26a638 M: 259e804d6df74e67a72e4206d7db691a300c775e 172.38.0.13:6379 slots:[10923-16383] (5461 slots) master 1 additional replica(s) S: 9b19170eea3ea1b92c58ad18c0b5522633a9e271 172.38.0.14:6379 slots: (0 slots) slave replicates 259e804d6df74e67a72e4206d7db691a300c775e [OK] All nodes agree about slots configuration.> >> Check for open slots... > >> Check slots coverage... [OK] All 16384 slots covered.
2、基于Docker的springboot项目部署
1、打包项目
2、编写Dockerfile
1 2 3 4 5 FROM java:8 COPY *.jar /app.jar CMD ["--server.port=8080" ] EXPOSE 8080 ENTRYPOINT ["java" , "-jar" , "/app.jar" ]
3、构建镜像
1 2 3 # 1.复制jar和DockerFIle到服务器 # 2.构建镜像 $ docker build -t xxxxx:xx .
4、发布运行
1 docker run -p 8080:8080 -t springboot/web-app-template 运行
十、Docker Compose
1、简介
Compose 是用于定义和运行多容器 Docker 应用程序的工具。通过 Compose,您可以使用 YML 文件来配置应用程序需要的所有服务。然后,使用一个命令,就可以从 YML 文件配置中创建并启动所有服务。
Compose 使用的三个步骤:
使用 Dockerfile 定义应用程序的环境。
使用 docker-compose.yml 定义构成应用程序的服务,这样它们可以在隔离环境中一起运行。
最后,执行 docker-compose up 命令来启动并运行整个应用程序。
2、安装
1 2 3 4 5 6 7 8 9 10 11 # 官网提供 (下载很慢) curl -L "https://github.com/docker/compose/releases/download/1.26.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose # 国内地址 curl -L https://get.daocloud.io/docker/compose/releases/download/1.25.5/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose# 授予可执行权限 chmod +x /usr/local/bin/docker-compose# 测试是否安装成功 docker-compose --version
3、yaml
官方yaml样例及配置语法:https://docs.docker.com/compose/compose-file/compose-file-v3/#compose-file-structure-and-examples
菜鸟教程相关:https://www.runoob.com/docker/docker-compose.html
执行流程:
创建网络
执行Docker-compose.yaml
启动服务
4、部署自己项目
1、编写项目微服务
2、Dockerfile构建镜像
1 2 3 4 5 FROM java:8 COPY *.jar /app.jar CMD ["--server.port=8080" ] EXPOSE 8080 ENTRYPOINT ["java" , "-jar" , "/app.jar" ]
3、docker-compose.yml编排项目
1 2 3 4 5 6 7 8 9 10 11 12 version '3.8' services: xiaofanapp: build: . image: myapp depends_on: - redis ports: - "8080:8080" redis: image: "library/redis:alpine"
4、运行
1 2 3 4 docker-compose up # 运行 docker-compose up -d # 后台运行 docker-compose down # 关闭容器 docker-compose up --build # 重新构建
十一、Docker Swarm
需要购买多态服务器,或多台虚拟机!
推荐去阿里云或腾讯云购买按量付费的4台1h2g即可!
1、简介
Docker Swarm 是 Docker 的集群管理工具。它将 Docker 主机池转变为单个虚拟 Docker 主机。 Docker Swarm 提供了标准的 Docker API,所有任何已经与 Docker 守护程序通信的工具都可以使用 Swarm 轻松地扩展到多个主机。
支持的工具包括但不限于以下各项:
Dokku
Docker Compose
Docker Machine
Jenkins
2、Swarm集群搭建
工作机制:
如下图所示,swarm 集群由管理节点(manager)和工作节点(work node)构成。
swarm mananger :负责整个集群的管理工作包括集群配置、服务管理等所有跟集群有关的工作。
work node :主要负责运行相应的服务来执行任务(task)。
1 2 3 4 5 6 7 8 9 10 11 12 docker swarm init --help ip addr # 获取自己的ip(用内网的不要流量) [root@iZ2ze58v8acnlxsnjoulk5Z ~]# docker swarm init --advertise-addr 172.16.250.97 Swarm initialized: current node (otdyxbk2ffbogdqq1kigysj1d) is now a manager. To add a worker to this swarm, run the following command: docker swarm join --token SWMTKN-1-3vovnwb5pkkno2i3u2a42yrxc1dk51zxvto5hrm4asgn37syfn-0xkrprkuyyhrx7cidg381pdir 172.16.250.97:2377 To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instructions. [root@iZ2ze58v8acnlxsnjoulk6Z ~]# docker swarm join --token SWMTKN-1-3vovnwb5pkkno2i3u2a42yrxc1dk51zxvto5hrm4asgn37syfn-0xkrprkuyyhrx7cidg381pdir 172.16.250.97:2377 This node joined a swarm as a worker.
docker swarm init:初始化结点
docker swarm join:加入一个结点!
docker swarm join-token manager:获取manger token令牌
docker swarm join-token worker:获取worker token令牌
docker node ls:查看节点信息
docker swarm leave:暂时离线,Status状态会改为Down
Manager Status:
Leader:表示是一个manager
Reachable:表示是另一个manager,且该服务正常
Unreachable:表示是另一个manager,但服务不正常
空:表示是一个worker
3、Raft协议
Raft协议:保证大多数 (指的是大于百分之五十即可)结点存活才可以使用,至少要有两台活着才能正常使用,集群至少要有3台manager!
例:双主双从时:将第一个Leader的docker停止后,就只有一个Reachable的主机无法判断是自己挂了还是别人挂了,即内部选举无法判断!大于三台才好判断!
4、docker service
操作集群,控制一个集群中的所有服务器就得使用docker service命令,可以用于动态扩缩容器!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 docker run # 容器启动! 不具有扩缩容器 docker service # 集群启动! 具有扩缩容器,滚动更新! docker service --help # 查看服务参数# 整个集群创建nginx服务,不一定是哪台创建,动态的 docker service create -p 80:80 --name mynginx nginx docker service ps 服务名 # 查看服务,服务在哪个节点上 docker service ls # 列出服务,查看副本数 docker service rm 服务名 # 移除# 创建副本 可以创建很多 内存足够即可 动态分配创建(不一定哪台会创建多少台) # 数字减小也会动态的将多的副本停掉! docker service update --replicas 3 my-nginx # 不会rm容器,只是stop docker service scale my-nginx=5 # 会rm容器# 查看服务具体信息 docker service inspect --pretty 服务名# 停止某个节点接收新的任务 docker node update --availability drain swarm-worker1# 重新激活节点 docker node update --availability active swarm-worker1