Docker:
学习目录
学习内容:
- 初识Docker
- Docker的基本操作
- Dockerfile自定义镜像
- Docker-Compose
- Docker镜像仓库
1.初始Docker:
- 什么是Docker?
- Docker和虚拟机的区别
- Docker架构
- 安装Docker
1.1.什么是Docker?
项目部署的问题:
大型项目组件较多,运行环境也较为复杂,部署时会碰到一些问题:
这些服务会依赖于各种各样的应用,Node.js、Redis、RabbitMQ、MySQL等等,每一个服务的应用它们需要的依赖和函数库有差异,也有可能版本不同,所以依赖关系复杂,容易出现兼容性问题。
·依赖关系复杂,容易出现兼容性问题
·开发、测试、生产环境有差异
Docker如何解决依赖的兼容问题的?
- 将应用的Libs(函数库)、Deps(依赖)、配置与应用一起打包
- 将每个应用放到一个隔离容器去运行,避免互相干扰
不同环境的操作系统不同,Docker如何解决?我们先来了解下操作系统结构
比如Ubuntu系统上的MySQL应用放到CentOS系统上尝试运行,当MySQL去调用函数库时,代码是写死的,这个函数库在CentOS系统上根本不存在,肯定就程序报错,这就是应用不能跨系统运行的原因。
Docker如何解决不同系统环境的问题?
Docker将用户程序与所需要调用的系统(比如Ubuntu)函数库一起打包;
Docker运行到不同操作系统时,直接基于打包的库函数,借助于操作系统的Linux内核来运行。
Docker如何解决大型项目依赖关系复杂,不同组件依赖的兼容性问题?
- Docker允许开发中将应用、依赖、函数库、配置一起打包,形成可移植镜像
- Docker应用运行在容器中,使用沙箱机制,相互隔离
Docker如何解决开发、测试、生产环境有差异的问题
- Docker镜像中包含完整运行环境,包括系统函数库,仅依赖系统的Linux内核,因此可以在任意Linux操作系统上运行
本节小结:
Docker是一个快速交付应用、运行应用的技术:
1.可以将程序及其依赖、运行环境一起打包为一个镜像,可以迁移到任意Linux操作系统;
2.运行时利用沙箱机制形成隔离容器,各个应用互不干扰;
3.启动、移除都可以通过一行命令完成,方便快捷。
1.2.Docker和虚拟机的差别
虚拟机(virtual machine)是在操作系统中模拟硬件设备,然后运行另一个操作系统,比如在Windows 系统里面运行Ubuntu系统,这样就可以运行任意的Ubuntu应用了。
Docker和虚拟机的差异:
· docker是一个系统进程;虚拟机是在操作系统中的操作系统;
· docker体积小、启动速度快、性能好;虚拟机体积大、启动速度慢、性能一般。
1.3.Docker架构
镜像(lmage) : Docker将应用程序及其所需的依赖、函数库、环境、配置等文件打包在一起,称为镜像。
容器(Container)︰镜像中的应用程序运行后形成的进程就是容器,只是Docker会给容器做隔离,对外不可见。
容器想往MySQL存数据,只能先复制一份到自己的容器,在自己的容器中操作,这样就污染不了这个镜像,起到隔离的作用。将来基于镜像再创建一个容器,也是全新的里面都是空的。
镜像是只读的,所以跨域交给别人放心大胆的使用,也不会被感染。
DockerHub: DockerHub是一个Docker镜像的托管平台。这样的平台称为Docker Registry。
国内也有类似于DockerHub 的公开服务,比如网易云镜像服务、阿里云镜像库等。
Docker是一个CS架构的程序,由两部分组成:
- 服务端(server): Docker守护进程,负责处理Docker指令,管理镜像、容器等
- 客户端(client):通过命令或RestAPI向Docker服务端发送指令。可以在本地或远程向服务端发送指令。
本节小结:
镜像:
- 将应用程序及其依赖、环境、配置打包在一起
容器:
- 镜像运行起来就是容器,一个镜像可以运行多个容器
Docker结构:
- 服务端:接收命令或远程请求,操作镜像或容器
- 客户端:发送命令或者请求到Docker服务端
DockerHub:
- 一个镜像托管的服务器,类似的还有阿里云镜像服务,统称为DockerRegistry
1.4.Docker的安装
企业部署一般都是采用Linux操作系统,而其中又数CentOS发行版占比最多,因此我们在CentOS下安装Docker。
1.CentOS安装Docker
Docker CE 支持 64 位版本 CentOS 7,并且要求内核版本不低于 3.10, CentOS 7 满足最低内核的要求,所以我们在CentOS 7安装Docker。
1.1.卸载(可选,若以前安装错误,可以卸载)
如果之前安装过旧版本的Docker,可以使用下面命令卸载:
\ 反斜杠是命令太长了,换到下一行
yum remove docker \
docker-client \
docker-client-latest \
docker-common \
docker-latest \
docker-latest-logrotate \
docker-logrotate \
docker-selinux \
docker-engine-selinux \
docker-engine \
docker-ce
没有任何匹配,说明没装过docker
1.2.安装docker
首先需要大家虚拟机联网,安装yum工具
yum install -y yum-utils \
device-mapper-persistent-data \
lvm2 --skip-broken
运行耐心等待一下,安装完成
然后更新本地镜像源:配置阿里云的仓库
# 设置docker镜像源
yum-config-manager \
--add-repo \
https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
sed -i 's/download.docker.com/mirrors.aliyun.com\/docker-ce/g' /etc/yum.repos.d/docker-ce.repo
yum makecache fast
回车继续
回车后,出现这一段说明镜像源配好了
然后输入命令:
yum install -y docker-ce
docker-ce为社区免费版本。稍等片刻,docker即可安装成功。
课程中是108M,我这边是94M,弹幕中也有人说是96M,这个无伤大雅。
完成了
1.3.启动docker
Docker应用需要用到各种端口,逐一去修改防火墙设置。非常麻烦,因此建议大家直接关闭防火墙!(学习中这样使用没啥事,企业中肯定不行,无奈我也不会设置,只能跟着教程走,可以问问运维大佬)
启动docker前,一定要关闭防火墙后!!
启动docker前,一定要关闭防火墙后!!
启动docker前,一定要关闭防火墙后!!
# 关闭
systemctl stop firewalld
# 禁止开机启动防火墙
systemctl disable firewalld
可以查看防火墙状态
systemctl status firewalld
通过命令启动docker:
systemctl start docker # 启动docker服务
systemctl stop docker # 停止docker服务
systemctl restart docker # 重启docker服务
查看docker状态,很眼熟吧
systemctl status docker
然后输入命令,可以查看docker版本:
docker -v
可以查看到说明安装和启动都是没有任何问题的。
到此安装完毕!
此外继续看下一节
1.4.配置镜像加速
docker官方镜像仓库网速较差,我们需要设置国内镜像服务:
参考阿里云的镜像加速文档:https://cr.console.aliyun.com/cn-hangzhou/instances/mirrors
sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{
"registry-mirrors": ["https://hwaf3xix.mirror.aliyuncs.com"]
}
EOF
sudo systemctl daemon-reload
sudo systemctl restart docker
运行
查看
重新加载文件和重启docker,镜像加速就配置完成了
全部的安装彻底结束了
2.Docker基本操作:
- 镜像操作
- 容器操作
- 数据卷(容器数据管理)
2.1.镜像相关命令
- 镜像名称一般分两部分组成:[repository]:[tag]
tag:是版本 - 在没有指定tag时,默认是latest,代表最新版本的镜像
查看帮助文档,可以查看docker的所有命令了
docker --help
比如想看某个命令的作用,也可以这样查看
docker images --help
案例一:从DockerHub中拉取一个nginx镜像并查看
1.首先去镜像仓库搜索nginx镜像,比如DockerHub:
有一个示例,这就是拉取nginx镜像了
拉取完成,默认拉取的是最新版
拉取后,查看镜像
docker images
可以看到拉取成功了
案例二:利用docker save将nginx镜像导出磁盘,然后再通过load加载回来
步骤一:利用docker xx --help命令查看docker save和docker load的语法
步骤二:使用docker save导出镜像到磁盘
步骤三:使用docker load加载镜像
查看docker save
导出语句
docker save -o nginx.tar nginx:latest
导出成功了
ll 查看本地文件
接下来要导入,先移除文件
docker rmi nginx:latest
可以看到移除了
加载文件
docker load -i nginx.tar
不加 -q可以看到加载的日志,加了就看不到了,加载完成
再次查看又有了
本节小结:
镜像操作有哪些?
- docker images (查看本地镜像)
- docker rmi (删除)
- docker pull (拉取镜像)
- docker push (上传镜像)
- docker save (保存镜像)
- docker load (读取镜像)
2.2.镜像命令练习
练习: 去DockerHub搜索并拉取一个Redis镜像
1.去DockerHub搜索Redis镜像
2.查看Redis镜像的名称和版本
3.利用docker pull命令拉取镜像
4.利用docker save命令将redisatst打包为一个redis.tar包
5.利用docker rmi删除本地的redis:latest
6.利用docker load重新加载redis tar文件
这里没选版本是最新版,注意选择版本
DockerHub上都有提供
拉取Redis镜像
docker pull redis
运行成功
保存redis镜像
docker save -o redis.tar redis:latest
保存查看,保存成功
加载前先删除
docker load -i redis.tar
重新加载回来了,恭喜学会了
2.3.使用Docker-容器命令介绍
容器相关命令
2.4.使用Docker-容器命令案例1
案例: 创建运行一个Nginx容器
步骤一:去docker hub查看Nginx的容器运行命令
容器是完全隔离的,所以暴露一个端口供用户访问,
80:80,左边是宿主机端口,右边是容器端口
运行一个容器
docker run --name mn -p 80:80 -d nginx
容器唯一ID,一旦创建一定会有一个唯一ID,和容器名一样是全局唯一,一个标识的作用。
查看容器
docker ps
访问试试,这就是nginx的欢迎界面,记得访问自己的地址
查看容器日志
注意:mn是容器名称,根据自己的容器名称写
docker logs mn
持续跟踪日志,ctrl+c停止日志跟踪
docker logs mn -f
本节小结:
docker run命令的常见参数有哪些?
●–name:指定容器名称
●-p:指定端口映射(暴露一个端口,让外界访问容器)
●-d:让容器后台运行
查看容器日志的命令:
●docker logs
●添加-f参数可以持续查看日志
查看容器状态:
●docker ps
2.4.使用Docker-容器命令案例2
案例: 进入Nginx容器,修改HTML文件内容,添加“欢迎您"
步骤一 :进入容器。进入我们刚创建的nginx容器的命令为:
这是已运行的容器
进入容器命令
docker exec -it mn bash
进入静态文件夹目录命令
cd /usr/share/nginx/html
查看 index.html 文件命令
cat index.html
可以看到这个html的文件内容,选择把“Welcome to nginx!”改成“欢迎您”
修改文件命令
但是在容器内修改文件是不推荐的;
你会发现中文特别难打进去,所以复制吧,逐行复制运行,可以看到我的运行图;
第二行让它支持中文。
sed -i 's#Welcome to nginx#欢迎您#g' index.html
sed -i 's#<head>#<head><meta charset="utf-8">#g' index.html
运行结果,替换成功
停止容器命令
docker stop mn
查看所有的容器,默认情况下只展示运行中的容器
docker ps
加上 -a 展示所有容器
docker ps -a
可以看到容器状态是退出了
运行容器命令
docker start (运行) 容器名字
docker start mn
容器成功运行了
删除容器命令
docker rm(删除) 跟上容器名字
docker rm mn
不能删除运行中的容器,所以要先暂停下来,也可以强制删除运行中的容器
查看文档,加上 -f
强制删除运行中的容器命令
docker rm -f mn
运行查看结果
本节小结
查看容器状态:
- docker ps
- 添加-a参数查看所有状态的容器
删除容器:
- docker rm
- 不能删除运行中的容器,除非添加 -f 参数
进入容器:
- 命令是docker exec -it [容器名][要执行的命令]
- exec命令可以进入容器修改文件,但是在容器内修改文件是不推荐的
(在容器中修改是没有记录的)
2.5.使用Docker-容器命令练习
练习:
创建并运行一个redis容器,并且支持数据持久化
步骤一:到DockerHub搜索Redis镜像
步骤二:查看Redis镜像文档中的帮助信息
步骤三:利用docker run命令运行一个Redis容器
实现
步骤一:到DockerHub搜索Redis镜像
进去往下翻
运行redis
docker run --name mr -p 6379:6379 -d redis redis-server --appendonly yes
运行查看结果
使用工具创建连接,连接后数据都是空的,也是第一次创建,所以成功了
练习二: 进入redis容器,并执行redis-cli客户端命令,存入num=666
步骤一:进入redis容器
步骤二:执行redis-cli客户端命令
步骤三:设置数据num=666
实现
进入redis容器
docker exec -it mr bash
进入容器
进入redis
步骤二:执行redis-cli客户端命令
redis-cli
成功进入redis
往redis添加数据
步骤三:设置数据num=666
keys *
set num 666
运行成功
多了一条数据
在shell控制台,获取这个数据,也没有问题
get num
最后退出完事了
直接进入redis
这里原来是bash,是进入一个容器
它这边跟的是一个命令,是执行什么命令
所以这里跟上redis-cli,它也是一个命令,所以可以运行直接进入redis
docker exec -it mr redis-cli
这时候退出是直接退到宿主机了
2.6.使用Docker-数据卷命令
数据卷
容器与数据耦合的问题
数据卷(volume) 是一个虚拟目录,指向宿主机文件系统中的某个目录。
将来容器删了,数据卷还在,有新版本的,只要挂载在数据卷上就行了,可以共享以前旧的数据了。
数据卷操作的基本语法如下:
数据卷操作命令是一个二级命令,第一级是docker volume [COMMAND]这才是真正的命令了;
docker volume命令是数据卷操作,根据命令后跟随的command来确定下一步的操作:(常用命令)
create : 创建一个volume
inspect : 显示一个或多个volume的信息
ls : 列出所有的volume
prune : 删除未使用的volume
rm : 删除一个或多个指定的volume
案例
创建一个数据卷,并查看数据卷在宿主机的目录位置
查看帮助文档,命令就是上面介绍的那些
命令操作
docker volume create html # 创建数据卷
docker volume ls # 查看数据卷
docker volume inspect html # 查看在硬盘的位置,查看挂载点
删除数据卷方式有两种:
prune 删除未使用的数据卷
rm 删除指定的数据卷
prune命令
docker volume prune
运行结果
rm命令
docker volume rm html
运行结果
轻松学会,可以多练习,记它们的用处,方便之后使用
这个案例基本就掌握了
最后啰嗦一遍,总结:
数据卷的作用:
- 将容器与数据分离,解耦合,方便操作容器内数据,保证数
据安全
数据卷操作:
- docker volume create (创建数据卷)
- docker volume ls (查看数据卷)
- docker volume inspect (查看数据卷存储位置)
- docker volume rm (删除指定数据卷)
- docker volume prune (删除未使用的数据卷)
2.7.使用Docker-数据卷挂载案例1
我们在创建容器时,可以通过 -v 参数来挂载一个数据卷到某个容器目录
(之后图片不会有水印了,终于找到去水印的地方了,哈哈哈哈)
上图中只有 -v 暂时还没接触过,那它是什么呢?
它前半部分是数据卷,后半部分是容器内的目录;
将名为“html”的数据卷,挂载到容器的 /root/html 的目录下。
案例: 创建一个nginx容器,修改容器内的html目录内的index.html内容
需求说明:在案例:2.4.使用Docker-容器命令案例2 中,我们进入nginx容器内部,已经知道nginx的html目录的所在位置 、/usr/share/nginx/html 我们需要把这个目录挂载到html这个数据卷上,方便操作其中的内容。
提示: 运行容器时使用-v参数挂载数据卷
步骤:
1.创建容器并挂载数据卷到容器内的HTML目录
(请逐行运行,看着注释理解它)
docker volume create html # 创建html数据卷
docker ps -a # 查看容器
docker run --name mn -p 80:80 -v html:/usr/share/nginx/html -d nginx # 创建 nginx容器,并挂载到html数据卷
docker ps # 查看容器已创建
docker inspect html # 查看数据卷的位置
cd /var/lib/docker/volumes/html/_data # 进入数据卷
ls # 查看文件
2.进入html数据卷所在位置,并修改HTML内容
现在已经是进入html数据卷的所在位置,接下来就是修改html内容
可以使用命令行,也可以使用工具直接对文件进行修改。
打开文件后,可以随意修改了
保存验证结果
也可以cat命令查看效果
cat index.html
在没有数据卷的情况下会是什么样呢?
docker rm -f mn # 删除容器
docker volume prune # 删除数据卷
docker run --name mn -p 80:80 -v html:/usr/share/nignx/html -d nginx # 重新创建容器,并挂载到数据卷上,此时是没有html这个数据卷的,刚刚删除了
docker volume ls # 查看数据卷的时候,有了html这个数据卷
访问成功,内容也变回去了
这个运行结果说明,如果在做容器挂载到数据卷时,数据卷不存在,我们的docker非常智能,它自动帮我们把这个数据卷创建出来。
本节小结:
2.8.使用Docker-数据卷挂载案例2
案例:
创建并运行一个MySQL容器,将宿主机目录直接挂载到容器
实现思路如下:
1.在将课前资料中的mysql.tar文件上传到虚拟机,通过load命令加载为镜像
2.创建目录/tmp/mysql/data
3.创建目录/tmp/mysql/conf,将课前资料提供的hmy.cnf文件上传到/tmp/mysql/conf
4.去DockerHub查阅资料,创建并运行MySQL容器,要求:
- 挂载/tmp/mysql/data到mysql容器内数据存储目录
- 挂载/tmp/mysql/conf/hmy.cnf到mysql容器的配置文件
- 设置MySQL密码
使用拖拽的方式,加载mysql.tar,想用代码可以查阅一下前面 《2.1.镜像相关命令》这一节拉取镜像的命令。
加载成功
加载mysql镜像
docker load -i mysql.tar
查看镜像文件
记住mysql的版本,待会创建容器要用,你自己使用的版本如果和我不一样,记得改成自己的。
创建目录
多级创建目录
mkdir -p mysql/data
mkdir -p mysql/conf
根据课件把配置文件hmy.cnf放进 /tmp/mysql/conf 目录下。该课程来自黑马程序员发布在bilibili的视频,可以在评论里找到课件,找不到加我的QQ群: 698782799 下载。
可以进目录里查看。
来到DockerHub官方,查找MySQL
这语句不全,缺了端口和数据卷的挂载
修改一下他提供的语句
记得修改一下密码,这里放个样例
版本改成自己的
配置端口
挂载需要挂载配置目录和数据目录
docker run \
--name mysql \
-e MYSQL_ROOT_PASSWORD=123 \
-p 3306:3306 \
-v /tmp/mysql/conf/hmy.cnf:/etc/mysql/conf.d/hmy.cnf \
-v /tmp/mysql/data:/var/lib/mysql \
-d \
mysql:5.7.25
配置文件目录
配置文件挂载的位置
数据挂载的位置
运行,容器成功创建出来了
所有MySQL的数据都进入到data目录下了。
测试连接成功
案例结束
现在学了两种数据导入的方式了,一个基于数据卷,一个基于目录直接挂载。
数据卷挂载的方式对比
当我们用数据卷时,我们的docker会全自动帮我创建数据卷对应的目录,这样数据卷就指向了目录。
容器挂载时只需要挂载到数据卷,不用关心目录在哪里,这全交给docker去处理了。但这个劣势是目录不是我们创建的,找目录比较麻烦。(自动化隐藏细节)
第二种方式是目录挂载,目录是我们自己创建的,挂载的时候,容器直接挂载上去。(这个细节自己实现,没有自动化)
本节小结:
1.docker run的命令中通过-V参数挂载文件或目录到容器中:
- -v volume名称:容器内目录
- -v宿主机文件容器内文件
- -v宿主机目录容器内目录
2.数据卷挂载与目录直接挂载的
- 数据卷挂载耦合度低,由docker来管理目录,但是目录较深,不好找
- 目录挂载耦合度高,需要我们自己管理目录,不过目录容易寻找查看
3.Dockerfile自定义镜像
- 镜像结构
- Dockerfile语法
- 构建Java项目
镜像结构:
镜像是将应用程序及其需要的系统函数库、环境、配置、依赖打包而成。
简单的说就是:底层函数库–>环境配置–>依赖安装–>应用安装–>应用配置
本节小结:
镜像是分层结构,每一层称为一个Layer
- Baselmage层:包含基本的系统函数库、环境变量、文件系统
- Entrypoint: 入口,是镜像中应用启动的命令
- 其它:在Baselmage基础上添加依赖、安装程序、完成整个应用的
安装和配置
3.1.自定义镜像-Dockerfile
什么是Dockerfile?
Dockerfile就是一个文本文件,其中包含一个个的指令(Instruction),用指令来说明要执行什么操作来构建镜像。每一个指令都会形成一层Layer。
常见指令:
FROM 是指定一个基础镜像,一般是操作系统, FROM centos:7,就是基于centos:7去构建,或者其他系统,就是基于该系统去构建。
ENV (entry value)是环境变量,一般都是键值对,配好后,后续中都可以使用环境变量里面配置好的东西。比如一个目录,配好后都可以使用这个目录。
COPY 复制,比如本地有一个Java的项目包(jar包),需要复制到镜像里面去,都可以使用COPY这个指令复制进去。
RUN 是执行Linux的shell命令,一般都是安装命令,比如有一个依赖需要安装或者解压,都可以使用RUN后面跟上shell的命令就行了。
EXPOSE 是暴露端口,这不是真正暴露端口,之前-p这个才是宿主机和容器暴露什么端口,EXPOSE只是指定容器内监听的是什么端口,是给镜像使用者看的,比如看到的是8080,那-p 8080:8080(冒号后面这一部分就是8080,注意是冒号“:”后面)。
ENTPYPOINT 启动命令,一个镜像要有一个启动脚本,jar的启动脚本有些人可能有接触过,java -jar xx.jar(应该有人在命令控制台启动过吧,没启动过也没关系),ENTPYPOINT java -jar xx.jar。
更新详细语法说明,请参考官网文档: https://docs.docker.com/engine/reference/builder
案例:
基于Ubuntu镜像构建一个新镜像,运行一个java项目
步骤1:新建一个空文件夹docker-demo;
步骤2:拷贝课前资料中的docker-demojar文件到docker-demo这个目录;
步骤3:拷贝课前资料中的jdk8.tar.gz文件到docker-demo这个目录;
步骤4:拷贝课前资料提供的Dockerfile到docker-demo这个目录;
步骤5:进入docker-demo;
步骤6:运行命令:
dockerfile
# 指定基础镜像
FROM ubuntu:16.04
# 配置环境变量,JDK的安装目录
ENV JAVA_DIR=/usr/local
# 拷贝jdk和java项目的包
COPY ./jdk8.tar.gz $JAVA_DIR/
COPY ./docker-demo.jar /tmp/app.jar
# 安装JDK
RUN cd $JAVA_DIR \
&& tar -xf ./jdk8.tar.gz \
&& mv ./jdk1.8.0_144 ./java8
# 配置环境变量
ENV JAVA_HOME=$JAVA_DIR/java8
ENV PATH=$PATH:$JAVA_HOME/bin
# 暴露端口
EXPOSE 8090
# 入口,java项目的启动命令
ENTRYPOINT java -jar /tmp/app.jar
三个文件提前准备好
进入某个文件夹,创建docker-demo目录
#关于docker的笔记我暂时记这么多了,开发过程中现在更多的是用K8S管理docker,还有一种可视化的,因为这一块并不归于我管,所以我描述不了太多,至于更新嘛,周末我会找个时间把它更完的。
祝您学完将来事业飞黄腾达!