docker学习笔记
Docker 使用 Google 公司推出的 Go 语言 进行开发实现。
docker是linux容器的一种封装,提供简单易用的容器使用接口。它是最流行的Linux容器解决方案。
docker的接口相当简单,用户可以方便的创建、销毁容器。
docker将应用程序与程序的依赖,打包在一个文件里面。运行这个文件就会生成一个虚拟容器。
程序运行在虚拟容器里,如同在真实物理机上运行一样,有了docker,就不用担心环境问题了。
为何用docker


docker VS 传统虚拟机

如何解决环境配置的问题?
解决方案一 虚拟机
虚拟机也可以制作模板,基于模板创建虚拟机,保证环境问题一致
虚拟机(virtual machine)就是带环境安装的一种解决方案。它可以在一种操作系统里面运行另一种操作系统,比如在 Windows 系统里面运行 Linux 系统。应用程序对此毫无感知,因为虚拟机看上去跟真实系统一模一样,而对于底层系统来说,虚拟机就是一个普通文件,不需要了就删掉,对其他部分毫无影响。
虽然用户可以通过虚拟机还原软件的原始环境。但是,这个方案有几个缺点。
(1)资源占用多
虚拟机会独占一部分内存和硬盘空间。它运行的时候,其他程序就不能使用这些资源了。哪怕虚拟机里面的应用程序,真正使用的内存只有 1MB,虚拟机依然需要几百 MB 的内存才能运行。
(2)冗余步骤多
虚拟机是完整的操作系统,一些系统级别的操作步骤,往往无法跳过,比如用户登录。
(3)启动慢
启动操作系统需要多久,启动虚拟机就需要多久。可能要等几分钟,应用程序才能真正运行。
虚拟机的优点:
资源池:一个物理机的优点分配到了很多不同的虚拟机里
很容易拓展: 加物理机器/加虚拟机
很容易云化: 阿里云,腾讯云
解决方案二
现在:自从用上docker容器后,可以实现开发、测试和生产环境的统一化和标准化。
镜像作为标准的交付件,可在开发、测试和生产环境上以容器来运行,最终实现三套环境上的应用以及运行所依赖内容的完全一致。
由于虚拟机的诸多问题,Linux发展出了另一种虚拟化技术:Linux容器(Linux Containers,缩写LXC)
Linux容器不是模拟一个完整的操作系统,而是对进程进行隔离。在正常进程的外面套了一个保护层,对于容器里面进程来说,它接触的资源都是虚拟的,从而实现和底层系统的隔离。
(1)启动快
容器里面的应用,直接就是底层系统的一个进程,而不是虚拟机内部的进程。所以,启动容器相当于启动本机的一个进程,而不是启动一个操作系统,速度就快很多。
(2)资源占用少
容器只占用需要的资源,不占用那些没有用到的资源;虚拟机由于是完整的操作系统,不可避免要占用所有资源。另外,多个容器可以共享资源,虚拟机都是独享资源。
(3)体积小
容器只要包含用到的组件即可,而虚拟机是整个操作系统的打包,所以容器文件比虚拟机文件要小很多。
总之,容器有点像轻量级的虚拟机,能够提供虚拟化的环境,但是成本开销小得多。

docker的优势
更高效的利用系统资源
由于容器不需要进行硬件虚拟以及运行完整操作系统等额外开销,Docker 对系统 资源的利用率更高。
无论是应用执行速度、内存损耗或者文件存储速度,都要比传 统虚拟机技术更高效。因此,相比虚拟机技术,一个相同配置的主机,往往可以运 行更多数量的应用。
更快速的启动时间
传统的虚拟机技术启动应用服务往往需要数分钟,而 Docker 容器应用,由于直接 运行于宿主内核,无需启动完整的操作系统,因此可以做到秒级、甚至毫秒级的启 动时间。大大的节约了开发、测试、部署的时间。
一致的运行环境
开发过程中一个常见的问题是环境一致性问题。由于开发环境、测试环境、生产环 境不一致,导致有些 bug 并未在开发过程中被发现。
而 Docker 的镜像提供了除内 核外完整的运行时环境,确保了应用运行环境一致性,从而不会再出现 “这段代码 在我机器上没问题啊” 这类问题。
持续交付和部署
对开发和运维(DevOps)人员来说,最希望的就是一次创建或配置,可以在任意 地方正常运行。
使用 Docker 可以通过定制应用镜像来实现持续集成、持续交付、部署。开发人员 可以通过 Dockerfile 来进行镜像构建,并结合 持续集成(Continuous Integration) 系 统进行集成测试,
而运维人员则可以直接在生产环境中快速部署该镜像,甚至结合 持续部署(Continuous Delivery/Deployment) 系统进行自动部署。
而且使用 Dockerfile 使镜像构建透明化,不仅仅开发团队可以理解应用运行环 境,也方便运维团队理解应用运行所需条件,帮助更好的生产环境中部署该镜像。
更轻松的迁移
由于 Docker 确保了执行环境的一致性,使得应用的迁移更加容易。Docker 可以在 很多平台上运行,无论是物理机、虚拟机、公有云、私有云,甚至是笔记本,其运 行结果是一致的。
因此用户可以很轻易的将在一个平台上运行的应用,迁移到另一 个平台上,而不用担心运行环境的变化导致应用无法正常运行的情况。
docker三大概念
1 | 容器三大基本概念 |
docker镜像
1 | Docker镜像就是一个只读的模板。 |
image的分层存储
1 | 因为镜像包含完整的root文件系统,体积是非常庞大的,因此docker在设计时按照Union FS的技术,将其设计为分层存储的架构。 |
docker容器(container)
1 | image和container的关系,就像面向对象程序设计中的 类和实例一样,镜像是静态的定义(class),容器是镜像运行时的实体(object)。 |
docker仓库(repository)
1 | 仓库是集中存放镜像文件的场所。有时候把仓库和仓库注册服务器(Registry)混为一谈,并不严格区分。实际上,仓库注册服务器上往往存放着多个仓库,每个仓库中又包含了多个镜像,每个镜像有不同的标签(tag)。 |
docker Registry构建仓库
1 | Docker Registry 公开服务是开放给用户使用、允许用户管理镜像的 Registry 服 务。一般这类公开服务允许用户免费上传、下载公开的镜像,并可能提供收费服务 供用户管理私有镜像。 |
安装配置docker
CentOS安装docker
官方教程:
https://docs.docker.com/engine/install/centos/
1 | 1.卸载旧版本 |

系统环境准备docker最低支持centos7且在64位平台上,内核版本在3.10以上
1 | [root@oldboy_python ~ 10:48:11]#uname -r |
踩坑:执行docker run hello-world时出现timeout的解决办法
1 | [root@localhost un1queyan]# docker run hello-world |
在配置了阿里云镜像,挂梯子等方法都不起作用后,在更改虚拟机的DNS后成功执行
1 | [root@localhost un1queyan]# sudo vim /etc/resolv.conf |
将namespace改为8.8.8.8
1 | # Generated by NetworkManager |
执行docker run hello-world
1 | Hello from Docker! |
docker hello-world 执行成功!
踩坑2:dockerfile中yum卡住
告警:ip转发功能未打开,网络将无法生效
1 | echo 'net.ipv4.ip_forward=1' >> /etc/sysctl.conf` |
Run的执行流程和docker执行原理
Run的执行流程
底层原理
docker是怎样工作的
Docker是一个client-server结构的系统,Docker的守护进程运行在主机上。通过socket客户端访问
DockerServer接收到Docker-Client指令,就会执行这个命令。
Docker为什么比VM快
1、 Docker有比虚拟机更少的抽象层
2、 docker利用的是宿主机的内核, VM需要的是Guest OS
所以说,新建一个容器的时候,docker不需要像虚拟机一样重新加载一个操作系统的内核,避免引导,虚拟机加载的是 Guest OS, 分钟级别的, 而docker利用的是宿主机的操作系统,省略了这个复杂的过程, 秒级
docker的常用命令
帮助命令
1 | [root@docker ~]# docker --help # 万能命令 |
1 | docker version # 显示docker的版本信息 |
镜像命令
docker images查看所有本地主机上的镜像
1 | [root@localhost un1queyan]# docker images |
docker search搜索镜像
1 | [root@localhost un1queyan]# docker search mysql |
docker pull拉取镜像
1 | 下载镜像 docker pull 镜像名[:tag] |
容器命令
说明: 我们有了镜像才可以创建容器,linux, 下载一个centos镜像来测试学习
1 | [root@localhost un1queyan]# docker pull centos |
新建容器并启动
1 | docker run [可选参数] image |
列出所有的运行的容器
1 | docker ps 命令 |
退出容器
1 | exit # 直接容器停止并退出 |
删除容器
1 | docker rm 容器id, # 删除指定的容器,不能删除正在运行的容器 |
启动和停止容器的操作
1 | docker start 容器id # 启动容器 |
常用其他命令
后台启动容器
1 | 命令docker run -d 镜像名! |
查看日志
1 | docker logs -f -t --tail 容器 |
查看容器中进程信息
1 | 命令 docker top 容器 id |
查看镜像的元数据
1 | [root@localhost un1queyan]# docker inspect [root@localhost un1queyan]# docker top 0f3140f21fcb |
进入当前正在运行的容器
1 | 我们通常容器都是使用后台方式运行的,需要进入容器,修改一些配置 |
从容器内拷贝文件到主机上
1 | docker cp 容器id:容器内路径 目的地主机路径 |
小结
1 | attach Attach to a running container #当前shell下attach连接指定运行镜像 |
部署nginx
docker 安装nginx
1 | [root@localhost un1queyan]# docker images |
端口暴露的概念
docker部署tomcat
1 | 官方的使用 |
可视化
- portainer (先用这个)
1 | docker run -d -p 8088:9000 \ |
- Rancher(CI/CD再用)
什么是portainer?
Docker图形化界面管理工具!提供一个后台面板供我们操作
1 | docker run -d -p 8088:9000 \ |
Docker镜像讲解
镜像是什么
镜像是一种轻量级,可执行的独立软件包,用来打包软件运行环境和基于运行环境打包的软件骂他包含运行某个软件所需的所有内容,包括代码,运行时,库,环境变量和配置文件。
所有的应用直接打包成docker文件就可以直接跑起来
如何得到镜像
- 从远程仓库下载
- 朋友拷贝
- 自己制作一个dockerfile
Docker镜像原理
UnionFS(联合文件系统)
UnionFS(联合文件系统): Union文件系统(UnionFS)是一种分层、轻量级并且高性能的文件系统,它支持对文件系统的修改作为一次提交来一层层的叠加,同时可以将不同目录挂载到同一个虚拟文件系统下(unite several directories into a single virtual filesystem)。Union文件系统是Docker镜像的基础。镜像可以通过分层来进行继承, 基于基础镜像(没有父镜像), 可以制作各种具体的应用镜像。
特性: 一次同时加载多个文件系统,但从外面看起来,只能看到一个文件系统,联合加载会把各层文件系统叠加起来,这样最终的文件系统会包含所有底层的文件和目录。
Docker镜像加载原理
docker的镜像实际上由一层一层的文件系统组成,这种层级的文件系统UnionFS。
**bootfs(boot file system)**主要包含bootloader和kernel,bootloader主要是引导加载kernel,Linux刚启动时会加载bootfs文件系统,在Docker镜像的最底层是bootfs。这一层与我们典型的Linux/Unix系统是一样的, 包含boot加载器和内核。当boot加载完成之后整个内核就都在内存中了,此时内存的使用权已由bootfs转交给内核,此时系统也会卸载bootfs。
rootfs(root file system), 在bootfs之上。包含的就是典型Linux系统中的/dev, /proc, /bin, /etc等标准目录和文件。rootfs就是各种不同的操作系统发行版,比如Ubuntu,Centos等等。
平时我们安装虚拟机的CentOS都是好几个G,为什么docker这里才200M?
对于一个精简的OS,rootfs可以很小,只需要包括最基本的命令、工具和程序库就可以了,因为底层直接用Host的kernel,自己只需要提供rootfs就行了。由此可见对于不同的linux发行版,bootfs基本是一致的,rootfs会有差别,因此不同的发行版可以共用bootfs。
分层的镜像
以我们的pull为例,在下载的过程中我们可以看到docker的镜像好像是在一层一层的在下载
为什么docker镜像要采用这种分层结构呢
最大的一个好吃就是共享资源
比如:有多个镜像都从相同的base镜像构建而来,那么宿主机只需在磁盘上保存一份base镜像,同时内存中也只需加载一份base镜像,就可以为所有容器服务了。而且镜像的每一层都可以被共享。
- 镜像的特点
Docker镜像都是只读的
当容器启动时,一个新的可写层被加载到镜像的顶部。
这一层通常被称作为”容器层”,“容器层”之下的都叫”镜像层”。
commit镜像
1 | docker commit 提交一个容器成为一个新的副本 |
测试
1 | 启动一个默认的tomcat |
容器数据卷
什么是容器数据卷
docker的理念回顾
将应用和环境打包成一个镜像
数据如果都在容器中,容器删除,数据丢失 需求:数据可以持久化
MySQL,容器删除,删库跑路。 需求:MySQL数据可以存储在本地
容器之间可以有一个数据共享的技术!docker容器内的目录,同步到本地
这就是卷技术!目录 挂载,将我们容器内的目录,挂载到linux上面!
使用数据卷
方式一:直接使用命令来挂载 -v
1 | docker run -it -v 主机目录;容器内目录 |
持久化mysql
1 | 获取镜像 |
具名和匿名挂载
1 | 匿名挂载 |
所有docker容器内的卷,没有指定目录的情况下都是在 /var/lib/docker/volumes/juming-nginx/_data
1 | [root@localhost un1queyan]# cd /var/lib/docker/ |
我 们通过具名挂载可以方便找到我们的一个卷,大多数情况在使用的具名挂载
1 | 如何确定是具名挂载还是匿名挂载,还是指定路径挂载 |
拓展
1 | 通过 -v 容器内路径: ro rw 改变读写权限 |
初始dockerfile
Dockerfile就是用来构建docker镜像的构建文件!命令脚本
通过这个脚本生成镜像,镜像是一层一层的,脚本是一个一个命令,每个命令都是一层
方式二:
1 | # 创建一个dockerfile文件,名字可以随意,建议dockerfile |
1 | [root@localhost docker-test-volune]# docker build -f dockerfile1 -t un1queyan/centos:1.0 . |
1 | 启动自己写的容器 |
这个卷和外部一定有一个卷重复 匿名挂载
查看一下卷挂载的数据
测试一下刚才的文件
我们通常会构建自己的镜像
假设构建镜像没有挂载卷, 要手动镜像挂载 -v 卷名: 容器内路径
1 | [root@localhost home]# cd /var/lib/docker/volumes/cb7a9a6c7f4889b1780ac15274daecb3f74ba7de215d7b2c503ec7a8ae3f60c7/_data |
数据卷容器
多个mysql同步数据
多个mysql实现数据共享
1 | [root@localhost un1queyan]# docker run -d -p 3310:3306 -v /home/mysql/conf.d:/etc/mysql/conf.d -v /home/mysql/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 --name mysql01 mysql:5.7 |
结论:容器之间配置信息的传递,数据卷容器的声明周期一直持续到没有容器使用为止
但是一旦持久化到了本地,本地的数据是不会删除的
DockerFile
dockerfile是用来构建docker镜像的文件,命令参数脚本
构建步骤:
1、编写一个dockerfile文件
2、docker build 构建成为一个镜像
3、docker run运行镜像
4、docker push 发布镜像(DockerHub, 阿里云镜像仓库!)
查看一下官方是怎么做的
很多官方镜像都是基本包,很多功能都没有,我们通常会搭建自己的镜像
DockerFile构建过程
基础知识:
1、每个保留关键字(指令)都必须是大写字母
2、执行顺序从上到下执行
3、# 表示注释
4、每个指令都会创建提交一个新的镜像层,并提交!
dockerfile是面向开发的,我们以后要发布项目,做镜像,就需要编写dockerfile文件。
步骤:开发,部署,上线,运维
Docker镜像逐渐成为了企业交付的标准,必须掌握。
DockerFile:构建文件,定义了一切的步骤,源代码
DockerImages:通过DockerFile构建生成的镜像,最终发布和运行的产品
Docker容器:容器就是镜像运行起来提供服务器
DockerFile的指令
1 | FROM # 基础镜像,一切从这里开始构建 |
实战测试
Docker Hub 中 99% 镜像都是从这个基础镜像过来的 FROM scratch,然后配置需要的软件和配置来进行构建
创建一个自己的CentOS
1 | # 1 编写dockerfile的文件 |
之前:
我们增加之后的命令
CMD 和 ENTRYPOINT 区别
1 | CMD # 指定这个容器启动的时候需要运行的命令,只有最后一个会生效,可被替代 |
测试CMD
1 | [root@localhost dockerfile]# vim dockerfile-cmd-test |
测试ENTRYPOINT
1 | [root@localhost dockerfile]# vim dockerfile-cmd-entry |
制作Tomcat镜像
1.准备镜像文件tomcat、jdk压缩包
1 | [root@localhost tomcat]# vi readme.txt |
2.编写dockerfile文件,文件名使用官方命名:Dockerfile ,build的时候会默认寻找当前目录下的文件,不需要使用-f参数指定
1 | [root@localhost tomcat]# vim Dockerfile |
3.使用该Dockerfile构建镜像
1 | [root@localhost tomcat]# docker build -t diytomcat:1.0 . |
4.启动生成的镜像,构建Tomcat容器.
这里设置了数据卷,宿主机的/home/dockerfile/tomcat/test对应该容器的/usr/local/apache-tomcat-8.5.55/webapps/test。这样关于test项目的修复只需要在宿主机上修改就可以了,不需要进入到容器中修改。
1 | [root@localhost tomcat]# docker run -d -p 8088:8080 --name diytomcat -v /home/dockerfile/tomcat/test:/usr/local/apache-tomcat-8.5.55/webapps/test diytomcat:1.0 |
这是一个一个简单的HTML
Hello World!
6.访问测试,浏览器访问查看是否能正常访问如果页面显示乱码,就需要修改tomcat的server.xml文件
1 | <Connector port="8080" protocol="HTTP/1.1" |
发布镜像到DockerHub
1.登录https://hub.docker.com/ DockerHub官网进行注册
2.进行登录,docker login -u 用户名
登录命令
1 | [root@localhost dockerfile]# docker login --help |
3.使用docker push命令推送镜像到DockerHub上的仓库
1 | [root@localhost dockerfile]# docker tag 0975df661526 ethanhuang824/diytomcat:1.0 |
因为push的时候,镜像名前面需要加上用户名(ethanhuang824是我的用户名。如果用户名不是当前登录用户则会拒绝push请求),所以需要使用命令docker tag 镜像名 新的镜像名复制出一份镜像重新打个Tag。
发布镜像到阿里云容器服务
1.登录阿里云,找到容器镜像服务
2.创建命名空间
4.与上面DockerHub的操作类似,按官方提供的操作指南操作即可。
总结
.
利用dockerfile定制镜像
1 | FROM scratch #制作base image 基础镜像,尽量使用官方的image作为base image |
发布docker image到仓库
1 | 第一种,docker hub公有镜像发布 |
1 | 私有仓库 |
打包flask程序与dockerfile
1 | 确保app.py和dockerfile在同一个目录! |