前言
- 简单介绍Docker的概念
- 介绍Docker的安装
- Docker镜像操作
- Docker容器操作
- Docker数据卷,数据映射
- Docker自定影镜像
- DockerCompose批量启动镜像
- 搭建DockerRegistry私服(UI版本)
Docker概述
项目部署的问题
大型项目组件多,运行环境也较为复杂,部署时会碰到一些依赖:如Node,Redis,MQ等。
- 依赖关系复杂,容易出现兼容性问题
- 开发、测试、生产环境有差异
Docker解决问题
Docker技术
- 将应用的Libs(函数库)、Deps(依赖)、配置与应用一起打包
- 将每个应用放到一个隔离容器中去运行,避免互相干扰
Docker问题
问题: 但是依然会存在一个问题,基于不同的操作系统的应用,就算一起打包,在别的操作系统上也难以运行,原因是:不同操作系统自己有函数库,这些函数库再去调用linux内核。这些应用会不可避免地使用系统自带的函数库。
- 解决:Docker将用户程序与所需要的调用的系统(如Ubuntu)函数库一起打包。
这样可以保证:不同操作系统的应用在Docker中,只要使用相同的linux内核就能无痛使用。相反,如果操作系统内核不一样,这个容器内的应用就可能会失效。(比如基于linux内核的Redis镜像生成的容器,一样不可以在Windows上使用)
一句话概括:Docker是基于内核的沙箱隔离技术,和虚拟机不同。
问题提问总结:
Docker如何解决大项目依赖关系复杂,不同组件依赖的兼容性问题?
- Docker允许开发中将应用、依赖、函数库、配置一起打包,形成可移植镜像
- Docker应用运行在容器中,使用沙箱机制,项目隔离
Docker如何解决开发、测试、生产环境有差异的问题
- Docker镜像中包含完整运行环境,包括系统函数库,仅依赖系统的Linux内核,因此可以在任意Linux操作系统上运行
Docker是什么
Docker是一个快速交付应用、运行应用的技术:
- 可以将程序及其依赖、运行环境一起打包为一个镜像,可以迁移到任务Linux操作系统
- 运行时利用沙箱机制形成隔离容器,各个应用互不干扰
- 启动、移除都可以通过一行命令完成,方便快捷
Docker和虚拟机
虚拟机运用了 Hypervisor技术,模拟了操作系统的硬件(CPU,内存等),虚拟机相当于创造了一个完成的系统生态。
Docker是基于操作系统内核的,不能跨平台。
Docker优点:
- 性能好,接近原生性能
- 占用内存小和硬盘空间小
- 启动快,秒级启动
总结
- docker是一个系统进程;虚拟机是在操作系统中的操作系统
- docker体积小、启动速度快、性能好;虚拟机体积大、启动速度慢、性能一般
Docker架构
镜像和容器
镜像: Docker将应用程序及其所需的依赖、函数库、环境、配置等文件打包在一起,成为镜像。
容器:镜像中的应用程序运行后形成的进程就是容器,只是Docker会给容器做隔离,对外不可见。
- 镜像运行起来就是容器,一个镜像可以运行多个容器
镜像是只读的,不可写。
镜像平台
- DockerHub:DockerHub是一个Docker镜像的托管平台。称为Docker Registry
- 国内也有DockerHub的公开服务
- 也可以自己构建私有平台
架构
C/S架构。
- 服务端(server):Docker守护进程,负责处理Docker指令,管理镜像、容器等。
- 客户端(client):通过命令或RestAPI向Docker服务端发送指令。可以在本地或远程向服务端发送指令。
安装
Docker分为CE和EE两个版本,CE是社区版本,免费使用。
这里显示Docker CE在CentOS上的安装。
版本
DockerCE支持64位版本CentOS7,并且要求内核版本不低于3.10,CentOS7满足最低内核的要求,所里我们在CentOS7安装。
补充:笔者在mac装了,就不装虚拟机了,麻烦。
**特别注意:**Docker作为linux技术,实际是不适配Mac的,Mac上的docker本质上是运行在VM上,所以一些实际数据的挂载位置,并不和docker记录的相同,我们得先进入虚拟环境才行,比如数据卷的挂载位置`/var/lib/docker`mac上是没有的,这里不展开了,建议各位在Linux上进行。You need to keep in mind that Docker is still running inside a VM. The system paths are still relative to the VM, and not to your Mac.
启动Docker
因为Docker会用到各种各样的端口,因此自己练习是最好关闭防火墙。
1 | systemctl start docker |
配置镜像
阿里镜像源:阿里云官网教程
Docker操作
帮助:docker --help
或者docker [opt] --help
操作镜像
- 镜像名称一般分为两部门组成:【repository】:【tag】(mysql:5.7)
- 没有指定tag,默认为latest
镜像操作命令
这里建议用docker [opt] --help
一个个查看如何使用
- 创建镜像:
docker build
- 拉取镜像:
docker pull
- 查看镜像:
docker images
- 删除镜像:
docker rmi
- 分享镜像
- docker服务器:
docker push
- 用U盘拷贝:
docker save
,随后docker load
使用镜像
- docker服务器:
- 修改镜像名称:
docker tag
实操:创建nginx镜像
- 拉取:pull
1 | # 拉取 |
- 把镜像打包:save && remove
1 | # 1. save |
- 加载别人的镜像:load
1 | # 3. load |
操作容器
基本操作
1 | # 创建并且启动 |
进阶操作
1 | # 进入容器执行命令 |
案例:操作Ngnix容器
运行和查看日志
- 去dockerhub查看Nginx容器的运行命令
1 | docker run --name {containerName} -p {hostPort}:{containerPort} -d {imageName:[TAG]} |
docker run
:创建并运行一个容器--name
:容器的名称-p
:将宿主端口与容器端口映射,冒号左侧是宿主机端口,右侧是容器端口- 容器的端口取决于容器中应用的本身,nginx一般是80
-d
:后台运行容器{imageName:[TAG]}
:镜像名称,不加tag默认是latest
1 | # 基于nginx启动容器 |
- 查看日志
1 | docker logs {containerName} # 和tail差不多,可以 -f -n |
修改容器中ngnix配置
- 进入容器
1 | docker exec -it {containerName} bash |
docker exec
:进入容器内部,执行一个命令-it
:给当前进入的容器创建一个标准输入、输出终端,允许我们与容器交互bash
:进入容器后执行的命令,bash是一个linux终端交互命令
- 修改配置
- 在dockerhub里面找到nginx的配置在哪里
- 因为容器里面没有vi和vim,我们目前只能用
docker cp
来同步(后面可以数据卷直接在宿主机中修改然后容器同步)docker cp ngnix.conf my-nginx-container:/etc/nginx/nginx.conf
- 删除容器:
docker rm
- 运行中的容器
-f
删除
- 运行中的容器
注意
不推荐在容器内做文件的修改!!
练习:创建redis容器
1 | # 创建redis容器 |
容器数据操作
问题
容器与数据太过耦合
- 不便于修改
- 数据不可复用,数据修改对外不可见
- 升级维护困难,容器一旦删除,数据就丢失了
数据卷概念
数据卷(volume)是一个虚拟目录,指向宿主机文件系统中某个目录。
容器中的文件通过volume与宿主机中的文件形成映射,不管哪一方修改文件,都能自动同步。
- 配置同步
- 数据同步
数据卷操作
docker volume [COMMAND]
create
:创建一个volumeinspect
:显示一个或多个volume的信息ls
:列出所有的volumeprune
:删除所有未使用的volumerm
:删除一个或多个指定的volume
实操
1 | # 创建一个名为html的数据卷 |
基于数据卷挂载的文件映射
类似具名挂载。
- 创建容器时,可以通过
-v
参数来挂载一个数据卷到某个容器目录
1 | docker run --name {containerName} -v {volumeName}:{containerDir} -p 8080:80 {IMAGE_NAME} |
-v html:/root/html
:把html数据卷挂载到容器内的/root/html这个目录中
注意:Mac的数据挂载位置不是docker volume inspect html
中显示的挂载位置,因为Docker在mac上本身就是挂载在虚拟机上的。
要解决这个问题,可以查看:Where is /var/lib/docker on Mac/OS X 和 2021 Update: Easiest option is Justin’s repo and image。本质就是直接去访问Docker VM。
1 | docker run -it --rm --privileged --pid=host justincormack/nsenter1 |
Just run this from your Mac terminal and it’ll drop you in a container with full permissions on the Docker VM. This also works for Docker for Windows for getting in Moby Linux VM (doesn’t work for Windows Containers).
PS:
- 所以说,在mac上搞数据卷挂载,外部修改这一套就是画蛇添足,我们直接用
docker cp
把数据同步到docker VM里面就好(或者用下面将的目录直接挂载),别想着在mac外部改了。挂载数据卷的唯一好处就是可以在Docker Desktop for Mac中查看数据卷同步的内容。
宿主机目录直接挂载
- 类似匿名挂载。
- 注意:若有重名文件,这种方式会导致容器内内容被覆盖。
如果container启动时使用
-v {hostDir}:{containerDir}
,则docker会直接将宿主机的目录挂载到容器上- 可以是目录,也可以是文件
mac用这种方式是完全ok的,猜想是Docker VM完成了这样的文件映射
案例:创建并运行一个Mysql容器,将宿主机目录直接挂载到容器
提示:目录挂载与数据卷挂载的语法是类似的
- -v 【宿主机目录】:【容器内目录】
- -v 【宿主机文件】:【容器内文件】
步骤:
-e表示配置环境变量
,Mysql环境变量设置具体看:Environment Variables。
1 | # 拉取mysql |
两种挂载方式对比
- 数据卷:docker管理数据,宿主机目录docker创建
- 直接挂载:自己管理数据(Mac只推荐这一种)
数据卷管理总结
docker run的命令中通过
-v
参数挂载文件或目录到容器中:-v {volumne名称}:{容器内目录}
-v {宿主机文件}:{容器内文件}
-v {宿主机目录}:{容器内目录}
数据卷挂载和目录直接挂载
- 数据卷挂载耦合度低,由docker管理目录,但是目录较深,不好找(mac和windows直接歇菜,需要现金DockerVM里面)
- 目录挂载耦合度高,需要我们自己管理目录,不过目录容易寻找查看
Dockerfile自定义镜像
镜像结构
镜像是将应用程序及其需要的系统函数库、环境、配置、依赖打包而成。
- 镜像是分层结构,每一层称为一个Layer
- BaseImage层:包含基本的系统函数库,环境变量、文件系统
- Entrypoint:入口,镜像中应用启动的命令
- 其他:在BaseImage上添加依赖、安装程序、完成曾哥应用的安装和配置
Dockerfile
Dockerfile就是一个文本文件,其中包含一个个的指令(Instruction),用指令来说明要执行什么操作来构建镜像。每一个指令都形成一层Layer。
实践:基于Ubuntu镜像构建一个新镜像,运行java项目
- 本地新建文件夹
docker-demo
- 拷贝一个jar包到文件夹内
- 拷贝一个
jdk8.tar.gz
到文件夹内 - 生成一个Dockerfile到文件夹内
1 | ####### Dockerfile ####### |
- 在文件夹下运行
docker build -t cxy-docker-image-demo:1.0 ./
-t
:指定镜像的名称./
:指定Dockerfile所在的目录
- 此时镜像就已经被docker管理了,可以
save
也可以load
- 使用
docker run --name my-docker-demo -p 8090:8090 -d cxy-docker-image-demo:1.0
问题
如果用以上的Dockerfile构建微服务镜像,会有一个问题:对于每个java微服务,都要安装基础镜像和配置java环境,是不是过于繁琐了?如果对于每个微服务,我们期望只把jar包放进去就行,有没有好的方法?
解决:基于java:8-alpine镜像,将一个java项目构建为镜像
java:8-alpine是一个体积非常小的JDK镜像,包含了基础环境
- 生成Dockerfile
1 | # 指定基础镜像 |
DockerCompose
Docker Compose可以基于Compose文件帮我们快速的部署分布式应用,而无需手动一个个创建和运行容器!
Compose文件是一个文本文件,通过指令定义集群中的每个容器如何运行。
1 | version: "3.8" # DockerCompse 版本 |
总结:DockerCompose能够帮助我们快速部署分布式应用,无需一个个服务去构建镜像和部署。
案例:利用DockerCompose部署微服务
环境整理
- 整理目录:
- 每个微服务下文件夹有dokcerfile
1 | FROM java:8-alpine |
- Docker-compose.yml
1 | version: "3.2" |
- 注意:这里Dockerpose底层做了域名封装,用服务名代替ip,如我们每个微服务配置nacos地址要从【ip:8848】改成【nacos:8848】;mysql的url中的【ip】要改成【mysql】
- 另外:不建议用docker部署数据库
操作
- Maven打包成app.jar
- 打包时发现问题:多模块引用,找不到模块jar。
- 原因:因为maven会第一时间去本地和配置文件中查询,但是这两个地方都没有模块jar,只要先把父工程install就行了。
- 打包时发现问题:多模块引用,找不到模块jar。
- 拷贝进微服务文件夹
- 将
cloud-demo
文件夹上传到虚拟机,利用docker-compose up -d
部署
- PS:一般会先启动nacos,不然微服务启动比nacos快,会注册不上。如果没注册上用
docker-compose
重启。
搭建私有的镜像仓库
镜像仓库(Docker Registry)有公有和私有的两种形式:
- 公共仓库:例如Docker Hub
- 在本地搭建私有的Docker Registry,registry是Docker官放提供的一个做镜像仓库的镜像
- 第三方有一个依赖于Docker Registry的joxit/docker-registry-ui:static镜像来做图形化的管理
配置Docker信任地址
私服采用http协议,默认不被Docker信任,所以需要一个配置(Mac在桌面版配置就行)
1 | # 找到docker的配置文件 |
DockerCompose构建私服
1 | version: '3.0' |
推送镜像到私服
- (一定要记得重命名)重新tag本地镜像,名称前缀为私有仓库地址: {ip:port}/
1 | docker tag nginx:latest 127.0.0.1:8080/nginx:1.0 |
- 推送拉取
1 | docker push 127.0.0.1:8080/nginx:1.0 |
再次强调
- 推送本地镜像到仓库前都必须重命名(docker tag)镜像,以镜像仓库地址为前缀
- 镜像仓库推送前需要把仓库地址配置到docker服务的deamon.json文件中,被docker信任
- 推送使用docker push命令
- 拉取使用docker pull命令