Docker入门介绍
轻量容器引擎Docker
Docker是什么
Docker 是一个开源项目,诞生于 2013 年初,最初是 dotCloud 公司内部的一个业余项目。
它基于 Google 公司推出的 Go 语言实现,项目后来加入了 Linux 基金会,遵从了 Apache 2.0 协议,项目代码在GitHub 上进行维护
Docker 自开源后受到广泛的关注和讨论,以至于 dotCloud 公司后来都改名为 Docker Inc,Redhat 已经在其 RHEL6.5 中集中支持 Docker;Google 也在其 PaaS 产品中广泛应用。
Docker 项目的目标是实现轻量级的操作系统虚拟化解决方案,Docker 的基础是 Linux 容器(LXC)等技术。
了解Docker的前生LXC
Linux Container容器是一种内核虚拟化技术,可以提供轻量级的虚拟化,以便隔离进程和资源。
LXC为Linux Container的简写,可以提供轻量级的虚拟化,以便隔离进程和资源,而且不需要提供指令解释机制以及全虚拟化的其他复杂性,相当于C++中的NameSpace,容器有效地将由单个操作系统管理的资源划分到孤立的组中,以更好地在孤立的组之间平衡有冲突的资源使用需求。
与传统虚拟化技术相比,它的优势在于:
与宿主机使用同一个内核,性能损耗小;
不需要指令级模拟;
不需要即时(Just-in-time)编译;
容器可以在CPU核心的本地运行指令,不需要任何专门的解释机制;
避免了准虚拟化和系统调用替换中的复杂性;
轻量级隔离,在隔离的同时还提供共享机制,以实现容器与宿主机的资源共享
Linux Container提供了在单一可控主机节点上支持多个相互隔离的server container同时执行的机制,Linux Container有点像chroot,提供了一个拥有自己进程和网络空间的虚拟环境,但又有别于虚拟机,因为lxc是一种操作系统层次上的资源的虚拟化。
LXC与docker的关系
docker并不是LXC替代品,docker底层使用了LXC来实现,LXC将linux进程沙盒化,使得进程之间相互隔离,并且能够可控限制各进程的资源分配,在LXC的基础之上,docker提供了一系列更强大的功能。
Docker 的特点
容器化越来越受欢迎,因为容器是:
灵活:即使是最复杂的应用也可以集装箱化。
轻量级:容器利用并共享主机内核。
可互换:您可以即时部署更新和升级。
便携式:您可以在本地构建,部署到云,并在任何地方运行。
可扩展:您可以增加并自动分发容器副本。
可堆叠:您可以垂直和即时堆叠服务。
为什么使用Docker
作为一种新兴的虚拟化方式,Docker 跟传统的虚拟化方式相比具有众多的优势。
首先,Docker 容器的启动可以在秒级实现,这相比传统的虚拟机方式要快得多,其次,Docker 对系统资源的利用率很高,一台主机上可以同时运行数千个 Docker 容器。
Docker的优势
具体说来,Docker 在如下几个方面具有较大的优势。
更高效的利用系统资源
由于容器不需要进行硬件虚拟以及运行完整操作系统等额外开销,Docker对系统资源的利用率更高,无论是应用执行速度,内存消耗以及文件存储速度,都要比传统虚拟机技术更高效,因此,相比虚拟机技术,一个相同配置的主机,往往可以运行更多数量的应用。
更快速的启动时间
传统的虚拟机技术启动应用服务往往需要数分钟,而Docker容器应用,由于直接运行与宿主内核,无须启动完整的操作系统,因此可以做到秒级,甚至毫秒级的启动时间,大大的节约了开发,测试,部署的时间。
一致的运行环境
开发过程中一个常见的问题是环境一致性问题,由于开发环境,测试环境,生产环境不一致,导致有些bug并未在开发过程中被发现,而Docker的镜像提供了除内核外完整的运行时环境,确保了应用运行环境一致性。
持续交付和部署
对于开发和运维人员来说,最希望的就是一次创建或配置,可以在任意地方正常运行。
使用Docker可以通过定制应用镜像来实现持续集成,持续交付,部署,开发人员可以通过Dockerfile来进行镜像构建,并结合持续集成系统进行集成测试,而运维人员则可以在生产环境中快速部署该镜像,甚至结合持续部署系统进行自动部署
更轻松的迁移
由于Docker确保了执行环境的一致性,使得应用的迁移更加容易,Docker可以在很多平台上运行,无论是物理机,虚拟机,公有云,私有云,甚至是笔记本,其运行结果是一致的,因此用户可以很轻易的将在一个平台上运行的应用,迁移到另一个平台上,而不用担心运行环境的变化导致应用无法正常运行的情况。
缺点
隔离性
基于hypervisor的虚机技术,在隔离性上比容器技术要更好,它们的系统硬件资源完全是虚拟化的,当一台虚机出现系统级别的问题,往往不会蔓延到同一宿主机上的其他虚机,但是容器就不一样了,容器之间共享同一个操作系统内核以及其他组件,所以在收到攻击之类的情况发生时,更容易通过底层操作系统影响到其他容器。
性能
不管是虚机还是容器,都是运用不同的技术,对应用本身进行了一定程度的封装和隔离,在降低应用和应用之间以及应用和环境之间的耦合性上做了很多努力,但是随机而来的,就会产生更多的网络连接转发以及数据交互,这在低并发系统上表现不会太明显,而且往往不会成为一个应用的瓶颈(可能会分散于不同的虚机或者服务器上),但是当同一虚机或者服务器下面的容器需要更高并发量支撑的时候,也就是并发问题成为应用瓶颈的时候,容器会将这个问题放大,所以,并不是所有的应用场景都是适用于容器技术的。
存储方案
容器的诞生并不是为OS抽象服务的,这是它和虚机最大的区别,这样的基因意味着容器天生是为应用环境做更多的努力,容器的伸缩也是基于容器的这一disposable特性,而与之相对的,需要持久化存储方案恰恰相反。 这一点docker容器提供的解决方案是利用volume接口形成数据的映射和转移,以实现数据持久化的目的,但是这样同样也会造成一部分资源的浪费和更多交互的发生,不管是映射到宿主机上还是到网络磁盘,都是退而求其次的解决方案。
对比传统虚拟机
Docker版本
随着Docker的不断流行与发展,docker公司(或称为组织)也开启了商业化之路,Docker 从 17.03版本之后分为 CE(Community Edition) 和 EE(Enterprise Edition),我们来看看他们之前的区别于联系。
版本区别
Docker EE
Docker EE由公司支持,可在经过认证的操作系统和云提供商中使用,并可运行来自Docker Store的、经过认证的容器和插件。
Docker EE提供三个服务层次:
大家可在该页查看各个服务层次的价目:https://www.docker.com/pricing
Docker CE
Docker CE是免费的Docker产品的新名称,Docker CE包含了完整的Docker平台,非常适合开发人员和运维团队构建容器APP
Docker公司认为,Docker CE和EE版本的推出为Docker的生命周期、可维护性以及可升级性带来了巨大的改进。
版本说明
在此之前docker的最新版本更新到docker17.13,而在1.13的基础之上,在2017年的3月1号开始,版本的格式变为如下
小结
Docker从17.03开始分为企业版与社区版,社区版并非阉割版,而是改了个名称;企业版则提供了一些收费的高级特性。
EE版本维护期1年;CE的stable版本三个月发布一次,维护期四个月;另外CE还有edge版,一个月发布一次。
Docker使用场景
Web 应用的自动化打包和发布。
自动化测试和持续集成、发布。
在服务型环境中部署和调整数据库或其他的后台应用。
从头编译或者扩展现有的OpenShift或Cloud Foundry平台来搭建自己的PaaS环境
Docker安装
卸载旧版本
较旧的 Docker 版本称为 docker 或 docker-engine ,如果已安装这些程序,请卸载它们以及相关的依赖项。
yum remove docker \ docker-client \ docker-client-latest \ docker-common \ docker-latest \ docker-latest-logrotate \ docker-logrotate \ docker-engine
安装Docker依赖环境
在新主机上首次安装 Docker Engine-Community 之前,需要设置 Docker 仓库,之后,您可以从仓库安装和更新 Docker。
yum install -y yum-utils \ device-mapper-persistent-data \ lvm2
设置 Docker 安装地址
在新主机上首次安装 Docker Engine-Community 之前,需要设置 Docker 仓库,之后,您可以从仓库安装和更新 Docker,使用以下命令来设置稳定的仓库(阿里云)
sudo yum-config-manager \ --add-repo \ http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
安装 Docker Engine-Community
安装最新版本的 Docker Engine-Community 和 containerd
sudo yum install -y docker-ce docker-ce-cli containerd.io
如果提示您接受 GPG 密钥,请选是。
Docker 安装完默认未启动,并且已经创建好 docker 用户组,但该用户组下没有用户。
Docker 镜像加速
阿里云镜像获取地址:https://cr.console.aliyun.com/cn-hangzhou/instances/mirrors,登陆后,左侧菜单选中镜像加速器就可以看到你的专属地址了:
配置daemon.json
您可以通过修改daemon配置文件/etc/docker/daemon.json来使用加速器
sudo mkdir -p /etc/dockersudo tee /etc/docker/daemon.json <<-'EOF'{ "registry-mirrors": ["https://xxxxx.mirror.aliyuncs.com"]}EOFsudo systemctl daemon-reloadsudo systemctl restart docker
启动 Docker
service docker start
验证docker服务
通过运行 hello-world 映像来验证是否正确安装了 Docker Engine-Community
docker run hello-world
运行该代码后首先会从仓库拉取
hello-world
镜像,然后运行该镜像,运行后会输出一个Hello from Docker!
开启Docker自动补全
使用docker时无法自动补全镜像名和其他参数,这样使用效率大大降低,下面是解决方法
bash-complete
yum install -y bash-completion
刷新文件
source /usr/share/bash-completion/completions/dockersource /usr/share/bash-completion/bash_completion
测试
输入
docker p
后docker会将可选项列出来
docker p
Docker架构
Docker总体架构为c/s架构,模块之间松耦合,包含了Client, Daemon, Registry, Graph, Driver, Libcontainer以及Docker Container
Docker的组件
Docker Client
是用户界面,它支持用户与Docker Daemon
之间通信Docker Daemon
Docker最核心的后台进程,运行于主机上,处理服务请求Docker registry
是中央registry,支持拥有公有与私有访问权限的Docker容器镜像的备份Docker Containers
负责应用程序的运行,包括操作系统、用户添加的文件以及元数据Docker Images
是一个只读模板,用来运行Docker容器DockerFile
是文件指令集,用来说明如何自动创建Docker镜像
Docker 基本概念
Docker 包括三个基本概念:
镜像
Docker 镜像是一个特殊的文件系统,除了提供容器运行时所需的程序、库、资源、配置等文件外,还包含了一些为运行时准备的一些配置参数(如匿名卷、环境变量、用户等),镜像不包含任何动态数据,其内容在构建之后也不会被改变。
分层存储
镜像只是一个虚拟的概念,其实际体现并非由一个文件组成,而是由一组文件系统组成,或者说,由多层文件系统联合组成。
Union FS
联合文件系统是(Union FS)是linux的存储技术,也是Docker镜像的存储方式, 它是分层的文件系统,将不同目录拉到同一个虚拟目录下,下图展示了Docker用Union FS 搭建的分层镜像:(比如最下层是操作系统的引导,上一层是Linux操作系统,再上一层是Tomcat,jdk,再上一层是应用代码)
这些层是只读的,加载完后这些文件会被看成是同一个目录,相当于只有一个文件系统。
我们可以通过docker info查看镜像的一些信息,可以看到存储驱动用的并不是Union FS 而是overlay2,overlay也是一个联合文件系统,所以上述主要介绍联合文件系统的概念,至于这些存储驱动的演变过程和优缺点
镜像构建时,会一层层构建,前一层是后一层的基础,每一层构建完就不会再发生改变,后一层上的任何改变只发生在自己这一层。(比如,删除前一层文件的操作,实际不是真的删除前一层的文件,而是仅在当前层标记为该文件已删除,在最终容器运行的时候,虽然不会看到这个文件,但是实际上该文件会一直跟随镜像,因此,在构建镜像的时候,需要额外小心,每一层尽量只包含该层需要添加的东西,任何额外的东西应该在该层构建结束前清理掉)
容器
镜像(Image)和容器(Container)的关系,就像是面向对象程序设计中的 类 和 实例 一样,镜像是静态的定义,容器是镜像运行时的实体,容器可以被创建、启动、停止、删除、暂停等。
容器的实质是进程,但与直接在宿主执行的进程不同,容器进程运行于属于自己的独立的命名空间,因此容器可以拥有自己的root文件系统、自己的网络配置、自己的进程空间,甚至自己的用户 ID 空间。
容器内的进程是运行在一个隔离的环境里,使用起来,就好像是在一个独立于宿主的系统下操作一样,这种特性使得容器封装的应用比直接在宿主运行更加安全,也因为这种隔离的特性,很多人初学 Docker 时常常会混淆容器和虚拟机。
前面讲过镜像使用的是分层存储,容器也是如此,每一个容器运行时,是以镜像为基础层,在其上创建一个当前容器的存储层,我们可以称这个为容器运行时读写而准备的存储层为容器存储层。
容器存储层的生存周期和容器一样,容器消亡时,容器存储层也随之消亡,因此,任何保存于容器存储层的信息都会随容器删除而丢失。
仓库
镜像构建完成后,可以很容易的在当前宿主机上运行,但是,如果需要在其它服务器上使用这个镜像,我们就需要一个集中的存储、分发镜像的服务,Docker Registry 就是这样的服务。
一个 Docker Registry 中可以包含多个仓库(Repository);每个仓库可以包含多个标签(Tag);每个标签对应一个镜像。
通常,一个仓库会包含同一个软件不同版本的镜像,而标签就常用于对应该软件的各个版本,我们可以通过<仓库名>:<标签>的格式来指定具体是这个软件哪个版本的镜像,如果不给出标签,将以latest作为默认标签。
以 Ubuntu 镜像为例,ubuntu是仓库的名字,其内包含有不同的版本标签,如,14.04,16.04,我们可以通过ubuntu:14.04,或者ubuntu:16.04来具体指定所需哪个版本的镜像,如果忽略了标签,比如ubuntu,那将视为ubuntu:latest
仓库名经常以三段式路径形式出现,比如heima.com/nginx-proxy:tag
,前者往往意味着 Docker Registry 多用户环境下的用户名,后者则往往是对应的软件名,但这并非绝对,取决于所使用的具体 Docker Registry 的软件或服务
Docker部署微服务
场景介绍
我们使用Docker完成一个微服务的搭建过程
整体架构如下
使用多个微服务进行项目部署测试
整体服务说明
我们总共涉及到三个微服务以及两个中间件
配置文件提取
因为我们在开发中需要频繁修改
application.yml
文件我们将配置项配置到pom
文件中打包时自动打到配置文件,这样可以用一个pom
文件控制多个不同的服务的配置文件项的修改
pom文件定义属性
我们需要在总
pom
文件定义全局配置,例如nacos
、mysql
等配置
<properties> <mysql.addr>192.168.64.153:3306</mysql.addr> <nacos.addr>192.168.64.153:8848</nacos.addr></properties>
配置编译选项
在子项目的pom文件的
build
构建配置中使用<filtering>true</filtering>
配置,这样就可以将我们的总pom中的配置编译进配置文件了
<build> <resources> <resource> <directory>src/main/java</directory> <includes> <include>**/*.xml</include> </includes> </resource> <resource> <directory>src/main/resources</directory> <filtering>true</filtering> </resource> </resources></build>
配置文件配置
在子项目的
application.yml
配置文件中注意使用@xxx@
占位符来配置编译占位配置,下面的配置就是用了@@
占位符编译后会将pom中的配置编译到配置文件中
server: port: @project.server.prot@spring: application: name: learn-docker-storage ######################### 数据源连接池的配置信息 ################# datasource: type: com.alibaba.druid.pool.DruidDataSource driverClassName: com.mysql.jdbc.Driver url: jdbc:mysql://@db.addr@/employees?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC username: root password: root initialSize: 10 minIdle: 20 maxActive: 100 maxWait: 60000 #### nacos 配置####### cloud: nacos: server-addr: @nacos.addr@mybatis: mapper-locations: classpath:mapper/*.xml type-aliases-package: com.heima.module.p
编译测试
配置完后编译项目后,可以进入target目录下查看编译后的配置文件
我们看到maven已经帮我们将配置编译进了配置文件中了