Docker
大型项目组件较多,运行环境也较为复杂,部署时会碰到一些问题:
-
依赖关系复杂,容易出现兼容性问题
-
开发、测试、生产环境有差异
1.什么是Docker?
大型项目组件很多,运行环境复杂,部署时会遇到各种问题,各个应用依赖各不相同,版本不同等,linux系统不同等...部署时非常复杂,效率很低。
Docker如何解决依赖兼容的问题?
-
将应用的Libs(函数库)、Deps(依赖)、配置与应用一起打包
-
将每个应用放到一个隔离容器去运行,避免互相干扰
虽然解决了不同应用的兼容问题,但是开发、测试等环境会存在差异,操作系统版本也会有差异,怎么解决这些问题呢?
linux系统的原理
分为3层,系统应用层(ubuntu/centos等),linux内核(所有Linux系统使用的都是linux系统内核),计算机硬件;
内核:内核负责与硬件交互,对上层提供内核指令,用于操作硬件;
系统应用:操作系统本身提供的应用、函数库。这些函数库是对内核指令的封装,使用更加方便;
应用于计算机交互的流程如下:
1)应用调用操作系统应用(函数库),实现各种功能
2)系统函数库是对内核指令集的封装,会调用内核指令
3)内核指令操作计算机硬件
由于系统应用不同,因此ubuntu的一个应用安装到centos系统上可能无法执行(提示找不到函数等),因此Docker提供了解决方案:
- Docker将用户程序与所需要调用的系统(比如Ubuntu)函数库一起打包
- Docker运行到不同操作系统时,直接基于打包的函数库,借助于操作系统的Linux内核来运行
2.Docker与虚拟机的区分?
Docker可以让一个应用在任何操作系统中非常方便的运行。而以前我们接触的虚拟机,也能在一个操作系统中,运行另外一个操作系统,保护系统中的任何应用。
虚拟机 (virtual machine)是在操作系统中模拟硬件设备,然后运行另一个操作系统,比如在 Windows 系统里面运行 Ubuntu 系统,这样就可以运行任意的Ubuntu应用了。
Docker仅仅是封装函数库,并没有模拟完整的操作系统,如图:
二者的性能指标对比:
综上所述,在实际的开发部署中通常Docker>虚拟机。
3.Docker架构
镜像
就是把一个应用在硬盘上的文件、及其运行环境、部分系统函数库文件一起打包形成的文件包。这个文件包是只读的。
容器
镜像中的应用程序运行后形成的进程就是,只不过要隔离起来。因此一个镜像可以启动多次,形成多个容器进程。
开源应用程序非常多,打包这些应用往往是重复的劳动。为了避免这些重复劳动,人们就会将自己打包的应用镜像,例如Redis、MySQL镜像放到网络上,共享使用,就像GitHub的代码共享一样。
-
DockerHub:DockerHub是一个官方的Docker镜像的托管平台。这样的平台称为Docker Registry。
我们一方面可以将自己的镜像共享到DockerHub,另一方面也可以从DockerHub拉取镜像:
Docker是一个CS架构的程序,由两部分组成:
-
服务端(server):Docker守护进程,负责处理Docker指令,管理镜像、容器等
-
客户端(client):通过命令或RestAPI向Docker服务端发送指令。可以在本地或远程向服务端发送指令。本地直接使用指令即可,远程使用RestApi发送请求。
4.Docker的安装
企业部署使用最多的时linux系统(Centos最多)
使用虚拟机安装CentOS7系统(满足了Docker CE对linux内核的最低要求)
1.卸载旧版Docker
如果虚拟机中可能存在旧版Docker,则需要删除旧的docker中相关内容
sh
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
2.卸载旧版Docker
2.1 虚拟机联网
记得使用NAT
2.2 安装yum工具
sh
yum install -y yum-utils \
device-mapper-persistent-data \
lvm2 --skip-broken
2.3 设置docker镜像源
sh
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
2.4 下载以及安装docker-ce(社区免费版)
sh
yum install -y docker-ce
2.5 启动Docker(如果是在虚拟机上为了避免逐个关闭端口号可以直接关闭防火墙,并设置禁用防火墙)
sh
# 关闭
systemctl stop firewalld
# 禁止开机启动防火墙
systemctl disable firewalld
2.6 安装成功之后,查看版本
sh
docker -v
显示如下内容表名安装成功
2.7 新安装docker之后如果重启可能导致docker服务没有启动,报错如下,表示docker守护进程未启动:
Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?
此时在root权限下执行
sh
systemctl start docker
5.镜像的命令
首先来看下镜像的名称组成:
- 镜名称一般分两部分组成:[repository]:[tag]。
- 在没有指定tag时,默认是latest,代表最新版本的镜像
比如[mysql]:[8.33];
常用命令:
- 从dockerhub中拉取镜像
sh
# 比如拉取nginx1.2.5版本
docker pull nginx:1.25.4
- 查看本地镜像
sh
docker images
- 导出镜像到磁盘
sh
# docker save -o [保存的目标文件名称] [镜像名称]
docker save -o nginx.tar nginx:1.25.4
如果只是指定保存文件名称,则会保存到当前目录下,如果想要保存到某个目录下可以直接指定:
sh
docker save -o ./download/nginx.tar nginx:1.25.4
- 从磁盘中加载镜像
sh
# docker load -i [某个位置的镜像包(如果是在当前目录下直接用镜像名即可]
docker load -i ./download/nginx.tar
- 删除镜像
sh
docker rmi nginx:1.25.4
6.容器的命令
基本命令使用
- 创建一个并运行一个nginx容器:
sh
docker run --name contrainerName -p 80:8080 -d ngxin:1.24.5
# docker run 创建并运行一个nginx容器
# --name contrainerName 为容器起一个名字
# -p 80:8080 宿主机与容器的端口映射,左侧是宿主机端口,右侧是容器端口
# -d ngxin:1.24.5运行的容器是哪一个(-d是放到后台邮件)
对端口映射的解读:
sh
由于容器是隔离的,所以并不能直接外部主机访问,外部主机可以访问宿主机(你可以将docker容器比作一个寄生虫,计生在宿主体内,外部无法与它直接交流,如果有必要交流,必须通过宿主作为中介,即外部告诉宿主,宿主告诉寄生虫),因此,将宿主机的端口与docker容器的端口作了一个映射之后,外部主机访问宿主机对应端口,宿主机端口再将对应的内容按照端口映射转发给docker容器
创建成功之后会返回该容器的ID:
- 查看所有容器的状态:
sh
docker ps
- 查看容器的日志
sh
# 普通日志输出
docker logs mv
# 持续跟踪日志输出
docker logs -f mv
- 让一个停止的容器再次运行
sh
docker start mv
- 停止一个容器的运行
sh
docker stop mv
- 暂停(挂起)一个容器
sh
docker pause mv
- 将暂停(挂起)的容器拿下来继续运行
sh
docker unpause mv
nginx容器创建之后,直接访问虚拟机对应的端口号:
进入容器,修改文件
进入容器。进入我们刚刚创建的nginx容器的命令为:
sh
docker exec -it mn bash
# docker exec 进入容器内部执行一个命令
# -it 给当前进入的容器一个标准输入,输出终端,允许我们与容器交互
# mn 我们要进入容器的名称
# bash 进入容器之后执行的命令
进入nginx默认页面的目录:
sh
cd /usr/share/nginx/html
由于docker容器是阉割版的"系统",只提供了对应的镜像文件,因此不会提供vi等编辑器,如果要在里边修改内容,需要使用sed替换命令。
sh
# sed命令详解
sed command file
# commond 针对每行的内容进行处理
# -i 直接修改文件内容,而不是输出到屏幕上
# -e 直接在命令行模式上进行sed的操作编辑
# s 替换,将文件原内容替换为新内容。举例:s/old/new/g "/"是分割符号,用来区分新内容与旧内容的,也开始使用别的符号比如:"#"
# g 表示行内全面替换
# file 要处理的文件,如果忽略该参数,会将标准输入作为对象进行处理
替换内容命令:
sh
sed -i -e 's/传智教育欢迎您/NiHao/g' -e 's#<head>#<head><meta charset="utf-8">#g' index.html
替换之后结果
7.数据卷
在之前的操作中,容器与数据耦合过高,当需要修改更新等操作时,非常麻烦;因此引入数据卷的概念。
数据卷:一个虚拟目录,指向宿主主机文件系统中的某个目录。
可以类比映射,数据卷挂载之后,对etc/nginx/conf就相当于对宿主机中的conf目录下进行操作,html目录同理。
当需要修改/更新等操作时修改的实际上是宿主主机文件系统中的目录下的内容,就算将容器删除之后,数据也是存在的,如果想要获取原来的数据,只需要再将数据卷挂载到宿主文件系统中对应的目录就行了。
常用命令
-
docker volume命令是数据卷操作,根据命令后跟随的command来确定下一步的操作:
-
create 创建一个volume
sh
# 创建一个名为html的数据卷
docker volume create html
- inspect 显示一个或多个volume的详细信息
sh
docker volum inspect html
在该命令中我们可以查看该数据卷的详细信息,包括数据卷在宿主机中的存储位置:
可以看到该数据卷在宿主机中的实际位置是"/var/lib/docker/volumes/html/_data".
- ls 列出所有的volume
sh
docker volume ls
-
prune 删除未使用的volume
-
rm 删除一个或多个指定的volume
数据卷挂载案例
- 创建容器并挂载数据卷到容器内的目录
sh
docker run --name mv -v html:/usr/share/nginx/html -p 80:80 -d nginx
# 创建容器的命令与之前相同,-v html:/usr/share/nginx/html 挂载数据卷html到容器内的/usr/share/nginx/html目录上
进入html数据卷所在位置,并修改HTML内容
sh
# 查看html数据卷的位置
docker volume inspect html
# 进入该目录
cd /var/lib/docker/volumes/html/_data
# 修改文件
vi index.html
在宿主机下修改完成之后(或者说是在数据卷下修改之后),容器中的对应的文件也会同步修改。
数据卷挂载案例之二
容器不仅仅可以挂载数据卷,也可以直接挂载到宿主机目录上。关联关系如下:
- 带数据卷模式:宿主机目录 --> 数据卷 ---> 容器内目录
- 直接挂载模式:宿主机目录 ---> 容器内目录
目录挂载与数据卷挂载的语法是类似的:
- -v [宿主机目录]:[容器内目录]
- -v [宿主机文件]:[容器内文件]
案例:创建并运行一个MySQL容器,将宿主机目录直接挂载到容器
1.创建目录/tmp/mysql/,以及2个子目录:/tmp/mysql/data , /tmp/mysql/conf
sh
cd /tmp # /tmp已经存在
mkdir /mysql
mkdir /mysql/data
mkdir /mysql/conf
2.以mysql为例,首先拉取8.0.33版本的mysql镜像
sh
docker pull docker:8.0.33
3.查看镜像列表是否成功导入
sh
docker images
4.导入mysql的一个额外配置文件hmy.cnf
5.创建mysql容器
sh
docker run \
--name mysql \
-e MYSQL_ROOT_PASSWORD=123 \
-p 3306:3306 \
-v /tmp/mysql/conf/hmy.conf:/ect/mysql/conf.d/hmy.cnf \
-v /tmp/mysql/data:/var/lib/mysql \
-d \
mysql:8.0.33
运行成功之后,返回mysql容器ID,使用docker ps命令查看
然后在外部(你的主机)使用mysql客户端连接
提示连接成功则成功