容器化技术——Docker学习
Docker 是一个开源软件,用于开发应用、交付应用、运行应用。 Docker允许用户将基础设施中的应用单独分割出来,形成更小的颗粒(容器),从而提高交付软件的速度。
一、Docker初识
1.什么是Docker
- Docker 是一个开源的应用容器引擎,基于Go 语言实现并遵从 Apache2.0 协议开源。
- Docker 可以让开发者打包他们的应用以及依赖包到一个轻量级、可移植的容器中,然后发布到任何流行的 Linux 机器上,也可以实现虚拟化。
- 容器是完全使用沙箱机制,相互之间不会有任何接口(类似 iPhone 的 app),更重要的是容器性能开销极低。
2.Docker vs VM
- 传统的虚拟机模拟出一套硬件来运行操作系统,也就是在硬件层面实现虚拟化,通常启动速度比较忙,资源消耗比较大。
- Docker容器化技术则是在操作系统层面实现虚拟化,直接复用本地主机的操作系统,而传统虚拟机则是在硬件实现虚拟化。
3.Docker组成
Docker基本组成主要包括以下三部分内容:
- 镜像(image) —> 类模板
- 容器(container)—> 对象
- 仓库(repository)—> 镜像仓库
Docker image:镜像是只读的,镜像中包含有需要运行的文件。镜像用来创建container,一个镜像可以运行多个container;镜像可以通过commit命令、Dockerfile等方式创建,也可以从Docker hub/registry上下载。
Docker container:容器是可写的,也是Docker的运行组件,启动一个镜像就是一个容器,容器是一个隔离环境,多个容器之间不会相互影响,保证容器中的程序运行在一个相对安全的环境中。
Docker repository: 存储镜像的仓库,用户通过它来共享和管理Docker镜像,用户可以上传或者下载上面的镜像,官方地址为https://registry.hub.docker.com/,也可以搭建自己私有的Docker registry。
4.Docker优点
应用架构上,就比如那一个订购系统来举例子,本来是一个基本的静态网页用来电话订购,现在需要网络订购了,那么我们就需要引入DB,再然后为了提升性能,引入了类似Redis、Memcached、MQ缓存等中间件,到项目后期,发现单机不能满足性能要求了,然后引入了Nginx作为反向代理,总之,随着系统功能的日趋复杂,那么应用依赖就会逐渐复杂,不同组件的配置方法各不相同,运维人员进行应用配置可能会耗费大量时间。
应用部署上,Dockerfile的存在使得开发人员仅仅需要修改其配置文件就可以轻松构建具有不同依赖的镜像。同时保障了从开发、构建、测试、生成的一整套流程。
集群角度上,随着流量的逐渐增大,这个时候就要引入集群了,服务器由原来的一台变成两台,那么相同的配置在另一台主机进行相同的配置时间开销比较大,因此可以通过镜像来一键打包部署即可。
关于Docker优点,总结如下:
- 快速的应用部署和维护
- 更便捷的升级和扩缩容
- 更简单的系统运维
- 更高效的计算资源利用
- 支持多种操作系统,Windows、Mac和Debian等
5.Docker架构
关于官方文档中解释:Docker Architecture
Docker引擎(Docker Engine)是一个服务端-客户端结构的应用,主要有这些部分:Docker守护进程、Docker Engine API、Docker客户端。
- Docker守护进程(Docker daemons),也叫
dockerd
,是一个持久化的进程,用户管理容器。守护进程会监听Docker Engine API 的请求。 - Docker Engine API是用于与Docker守护进程交互用的的API。它是一个RESTful API,因此它不仅可以被Docker客户端调用,也可以被
wget
和curl
等命令调用。 - Docker客户端,也叫
docker
,是大部分用户与Docker交互的主要方式。用户通过客户端将命令发送给守护进程。命令会遵循Docker Engine API
6.Docker生态
Docker生态中还有一个非常重要的容器管理工具–Kubernetes,它是Google开源的用于在集群环境中管理、维护、自动扩展容器,通过Kubernetes可以很方便地在多个机器上管理和部署容器服务。现在已经得到IBM、Microsoft、RedHat等多个大公司的支持。
Docker现在出现了一个特殊的模式——swarm模式——可以用来管理容器集群。Docker Swarm允许使用Docker CLI运行swarm命令,因而很容易初始化一组容器,并向组中添加或删除容器。除了Docker Swarm,还有几个其他的容器协调管理器:
- Kubernetes,一个容器集群管理器。可以在你自己的服务器上或是在云上运行。
- DC/OS,一个特别的项目,提供了高级用户界面管理Docker容器。
- Nomad Project,一个部署和管理应用的软件,运行在Amazon ECS,DigitalOcean,Azure Container Service或Google云平台。
二、Docker安装
1. 命令行安装
这里测试环境是 Centos Linux 8版本,安装使用 yum
命令安装。
yum -y install docker-ce docker-ce-cli #下载Docker
docker version #查看docker版本号
docker images #存在的镜像
- TAG:版本号(默认最新)
- REPOSITORY: 镜像名字
- IMAGET ID : 镜像全局唯一ID
- CREATED: 镜像创建时间
- SIZE:镜像大小
2. 设置加速仓库
注册阿里云开发者账户,进入仓库镜像模块,获取仓库加速域名。
仓库(Repository)、注册服务器(Registry)、注册索引(Index)有何关系?
首先,仓库是存放一组关联镜像的集合,比如同一个应用的不同版本的镜像,注册服务器是存放实际的镜像的地方,注册索引则负责维护用户的账号,权限,搜索,标签等管理。注册服务器利用注册索引来实现认证等管理。
3. 配置普通用户管理Docker
由于需要使用普通用户对Docker进行管理,因此需要给普通用户配置Docker权限,根据 官方文档来进行配置。具体命令行如下:
sudo groupadd docker #加入Docker用户组
sudo usermod -aG docker $USER #将用户添加到用户组
newgrp docker #刷新权限
id $USER #查看用户情况
docker run hello-world #运行hello world测试
三、Docker基本使用
- 获取镜像
docker pull REPOSITORY:TAG
- 运行镜像
docker run IMAGE_ID
- 删除镜像
docker rmi IMAGE_ID
- 暂停容器
docker stop CONTAINER_ID
docker run -i 镜像ID #交互模式启动容器
## 常用参数
-i, --interactive Keep STDIN open even if not attached
--ip string IPv4 address (e.g., 172.30.100.104)
--ip6 string IPv6 address (e.g., 2001:db8::33)
--ipc string IPC mode to use
--isolation string Container isolation technology
--kernel-memory bytes Kernel memory limit
-p : 宿主机端口 :Docker运行端口
-P : 随机宿主机端口
-t : 命令终端
Docker虚悬镜像:仓库名、标签都为
前台启动和后台启动
docker run -d #守护式启动
docker run -i #前台式启动
#重新进入命令交互界面
docker exec -it 容器ID bashshell
docker attach 容器ID
区别:
- accatch 不会重新创建一个新的进程,使用
exec
会导致终端停止 - exec 会重新创建一个新的进程,不会导致终端停止,此种方法也是工作常用的
四、Docker网络
当 Docker 启动时,会自动在主机上创建一个 docker0
虚拟网桥,实际上是 Linux 的一个 bridge,可以理解为一个软件交换机。它会在挂载到它的网口之间进行转发。
同时,Docker 随机分配一个本地未占用的私有网段中的一个地址给 docker0
接口。它在内核层连通了其他的物理或虚拟网卡,这就将所有容器和本地主机都放到同一个物理网络。比如典型的 172.17.42.1
,掩码为 255.255.0.0
。此后启动的容器内的网口也会自动分配一个同一网段(172.17.0.0/16
)的地址。这里,我们可以在主机上执行ip addr
查看主机ip配置:
进入某一容器,容器内部查看发现容器IP:发现其也属于172.17
网段,因此验证上述的文档解释。
除bridge方式,Docker还支持host、container、none三种网络通信方式,使用其它通信方式,只要在Docker启动时,指定–net参数即可。
- host方式可以让容器无需创建自己的网络协议栈,而直接访问宿主机的网络接口,在容器中执行ip addr会发现与宿主机的网络配置是一样的,host方式让容器直接使用宿主机的网络接口,传输数据的效率会更加高效,避免bridge方式带来的额外开销,但是这种方式也可以让容器访问宿主机的隐私服务,可能会带来意想不到的安全问题,因此应谨慎使用host方式;
- container方式可以让容器共享一个已经存在容易的网络配置;
- none方式不会对容器的网络做任务配置,需要用户自己去定制。
外部访问容器
容器允许外部访问,可以在 docker run
时候通过 -p
或 -P
参数来启用。不管用那种办法,其实也是在本地的 iptable
的 nat 表中添加相应的规则。
docker run IMAGE_ID -p 8080:8081 #将container的8081端口开放给宿主机的8080端口,通过访问主机的8080端口就可访问到container的8081端口
容器访问外部
容器所有到外部网络的连接,源地址都会被 NAT 成本地系统的 IP 地址。这是使用 iptables
的源地址伪装操作实现的。
从下图可以看到,对172.18.0.0/16局域网下所有设备需要访问外部网络的时候,会经过NAT地址转换
五、Docker镜像构建
1. Commit命令
docker commit
支持扩展现有镜像,创建新的镜像,通常来说,commit
命令就是提交容器副本使之成为一个新的镜像
docker commit -m="提交的描述信息" -a="作者" 容器ID 要创建的目标镜像名:[标签名]
2. Dockerfile构建
Dockerfile也是生成Docker镜像的一种重要手段,也是常用的手段。它是一个文本文件,其中包含我们需要运行以构建 Docker 映像的所有命令。
Docker commit是通过增强原有镜像基础上,重新安装新功能。
Dockerfile, 本镜像需要一次性添加所有所需的依赖镜像
- 编写Dockerfile文件
- 执行Docker build构建镜像
- docker run启动镜像
构建流程
- docker从基础镜像运行一个容器
- 执行一条指令并对容器做出修改
- 执行类似docker commit的操作提交一个新的镜像层
- docker再基于刚提交的镜像运行一个新容器
- 执行dockerfile中的下一条指令直到所有指令都执行完成
生动概括:dockerfile(中药单子)–> images(中药) —> docker container(药汤)
六、Docker数据管理
Docker分层,联合文件系统。Docker由于是基于Linux上运行的,因此底层直接使用Host的kernel,自己需要提供rootfs就可以了。不同的发行版本由于bootfs
基本上是一致的,但是rootfs
会有差别,因此不同的发行版可以公用bootfs
。
1. 文件卷的作用
将Docker容器中的数据保存进宿主机中磁盘系统。也就是对数据的要求是持久化的。如果容器实例删除之后,容器内的数据自然就没有了。
因此Docker容器内部的数据可以备份+持久化到本地主机目录
docker run -it --privileged=true -v 宿主机目录:Docker目录 镜像名
- 数据卷可以在容器之间或者宿主机与容器之间共享数据
- 可以对容器里面的数据进行持久化或者备份
- 更好的管理文件
docker inspect 容器名 #查看容器详情
可以看到Docker Mounts下会计到自己挂载的路径规则
2. 容器卷的继承
docker run -it --privileged=true --volumes-from 容器父类名 --name 容器名
子容器集成父容器的挂载规则,如果父容器被kill或者stop,不会影响子容器的规则。
心中无女人,编码自然神,忘掉心上人,抬手灭红尘
七、Docker实战
这里我使用之前的软件实践项目来进行Docker从构建到部署一整套实验。
Step1:Maven打包
进入项目目录,在Terminal运行Maven命令,通过Maven构建SpringBoot Web项目,将其打成Jar包。
mvn package -Dmaven.test.skip=true
发现项目目录下生成了一个可执行Jar包,这里我们可以通过jar包来测试。
Step2:上传Jar包
将Jar包通过FTP工具上传到服务器~/healthySystem
目录下
Step3 :编写Dockerfile
~/healthySystem
目录下,使用vim Dockerfile
创建一个Dockerfile文件,然后在文件编辑如下内容:
#根据Java15为基础镜像
FROM openjdk:11.0.15-oraclelinux7
MAINTAINER tyf
#RUN yum install redis && yum install mysql
#将当前目录下jar包复制到Docker镜像中
#将需要额外加载的配置文件加入镜像
COPY *.jar /app.jar
COPY *.yml /application.yml
#暴露出的端口
EXPOSE 8079
ENTRYPOINT ["java", "-jar", "/app.jar" ~
修改完毕后,保存退出。
Step4:构建Docker镜像
在~/healthySystem
目录下执行:
docker build -t healthy:1.0 .
结果显示Successfully built ......
,构建Images成功
Step5: 测试镜像
docker run --name healthy --network host healthy:1.0 #执行新实例
执行docker ps
查看容器状态
打开服务器防火墙,访问http://81.68.239.206:8093/welcome.htm
,正常启动。
Step5: 上传至阿里云仓库
这里使用我们上述使用的阿里云镜像仓库和中心仓库,在阿里云镜像仓库创建完成相应的远程仓库后,按照官方操作步骤来完成镜像推送。
-
登陆至阿里云 Docker Registry
docker login --username=谭永锋nb registry.cn-shanghai.aliyuncs.com
-
更改镜像Tag
#docker tag [ImageId] registry.cn-shanghai.aliyuncs.com/sleepytans/webapp:[镜像版本号] docker tag 9e78dbdd6dd8 registry.cn-shanghai.aliyuncs.com/sleepytans/webapp:1.0
-
上传镜像
#docker push registry.cn-shanghai.aliyuncs.com/sleepytans/webapp:[镜像版本号] docker push registry.cn-shanghai.aliyuncs.com/sleepytans/webapp:1.0
-
登陆阿里云查看远程镜像仓库,显示上传成功。
Step6:测试部署
网站部署步骤:https://github.com/TanYongF/healthyDay
基本流程:
- 安装Mysql、Redis
- 配置项目配置文件
- 执行下面命令
- 访问
http://ip:8093
docker run --name healthy --network host registry.cn-shanghai.aliyuncs.com/sleepytans/webapp:1.0
八、实验总结
本次大作业通过学习Docker基本安装、数据管理、网络等基础知识,对Docker的诞生由来以及解决了多依赖项目部署复杂的问题,同时针对特定内容对Docker例如网络模式,其基于底层隔离和资源限制的基础——CGroup以及Namespace技术有了一定的理解。
同时又对之前的软件实习项目的部署引入Docker进行改造,通过编写Dockerfile以及Docker-compose文件构建出了项目对应的镜像并且上既然到了云端,从实践方面体会到了Docker对实际项目运维部署方面带来的巨大便捷。
由于自身的学习方向是Java后端方向,对于现在接触比较多的微服务、集群来讲,Docker等云原生工具大大降低配置部署难度,同时也让我对DevOps开发流程的理解逐渐加深,也促使我将将传统的开发思想逐渐转变成容器化思想。但是鉴于时间紧迫,对Docker底层原理的细节了解还不是很充分,同时对于业界比较流行的Kubernetes(k8s)等Docker容器编排工具还没有具体的体验学习,但是学无止境,未来我也会继续加深对其中云原生技术的深入学习,努力将自己打造成为新一代DevOps工程师。
参考资料
- Docker docs
- Docker访问宿主机
- Docker基本指令使用.菜鸟教程
- Docker入门.Meituan Tech
- https://www.xmind.net/m/RHSz/
- https://yeasy.gitbook.io/docker_practice/advanced_network
- iptables详解
- Docker.Wiki百科