Docker
1. 简介
1.1 什么是虚拟化
- 在计算机中,虚拟化(Virtualization)是一种资源管理技术,是将计算机的各种实体资源,如服务器、网络、内存及存储等,予以抽象、转换后呈现出来,打破实体结构间的不可切割的障碍,使用户可以比原本的组态更好的方式来应用这些资源。这些资源的新虚拟部分是不受现有资源的架构方式,地域或物理组态所限制。一般所指的虚拟化资源包括计算能力和资料存储
- 在实际的生产环境中,虚拟化技术主要用来解决高性能的物理硬件产能过剩和老的旧的硬件产能过低的重组重用,透明化底层物理硬件,从而最大化的利用物理硬件。对资源充分利用虚拟化技术种类很多,例如:软件虚拟化、硬件虚拟化、内存虚拟化、网络虚拟化(vip)、桌面虚拟化、服务虚拟化、虚拟机等等
1.2 什么是 Docker
- Docker 是一个开源项目,诞生于2013年初,最初是 dotCloud 公司内部的一个业余项目。它基于 Google 公司推出的 Go 语言实现。项目后来加入了 Linux 基金会,遵从了 Apache 2.0 协议,项目代码在Github(https://github.com/docker/docker)上进行维护
- Docker 自开源后受到广泛的关注和讨论,以至于 dotCloud 公司后来都改名为 Docker Inc。Redhat 已经在其 RHEL6.5 中集中支持 Docker;Google 也在其 PaaS 产品中广泛应用
- Docker 项目的目标是实现轻量级的操作系统虚拟化解决方案。Docker 的基础是 Linux 容器(LXC)等技术
- 在 LXC 的基础上 Docker 进行了进一步的封装,让用户不需要去关心容器的管理,使得操作更为简便。用户操作 Docker 的容器就像操作一个快速轻量级的虚拟机一样简单
1.3 为什么选择Docker?
更高效的利用系统资源
- 由于容器不需要进行硬件虚拟以及运行完整操作系统等额外开销,Docker 对系统资源的利用率更高。无论是应用执行速度、内存损耗或者文件存储速度,都要比传统虚拟机技术更高效。因此,相比虚拟机技术,一个相同配置的主机,往往以及运行更多数量的应用
更快速的启动时间
- 传统的虚拟机技术启动应用服务往往需要数分钟,而 Docker 容器应用,由于直接运行于宿主内核,无需启动完整的操作系统,因此可以做到秒级、甚至毫秒级的启动时间。大大节约了开发、测试、部署的时间
一致的运行环境
- 开发过程中一个常见的问题是环境一致性问题。由于开发环境、测试环境、生产环境不一致,导致有些bug并未在开发过程中被发现。而 Docker 的镜像提供了除内核外完整的运行时环境,确保了应用环境一致性,从而不会再出现【这段代码在机器上没问题啊】这类问题
持续交付和部署
- 对开发和运维(DevOps)人员来说,最希望的就是一次创建或配置,可以在任意地方正常运行
- 使用 Docker 可以通过定制应用镜像来实现持续集成、持续交付、部署,开发人员可以通过 Dockerfile 来进行镜像构建,并结合持续集成(Continuous Integration)系统进行集成测试,而运维人员则可以直接在生产环境中快速部署改镜像,甚至结合持续部署(Continuous Delivery/Deployment)系统进行自动部署
- 而且使用 Dockerfile 使镜像构建透明化,不仅仅开发团队可以理解应用运行环境,也方便运维团队理解应用运行所需条件,帮助更好的生产环境中部署该镜像
更轻松的迁移
- 由于 Docker 确保了执行环境的一致性,使得应用的迁移更加容易。Docker 可以在很多平台上运行,无论是物理机、虚拟机、公有云、私有云,甚至是笔记本,其运行结果是一致的。因此用户可以很轻易地将在有个平台上运行的应用,迁移到另一个平台上,而不用担心运行环境的变化导致应用无法正常运行的情况
更轻松的维护和扩展
- Docker 使用的分层存储已经镜像的技术,使得应用重复部分的复用更为容易,也使得应用的维护更新更加简单,基于基础镜像进一步扩展镜像也变得非常简单。此外,Docker 团队同各个开源项目团队一起维护了一大批高质量的官方镜像,既可以直接在生产环境使用,又可以作为基础进一步定制,大大大降低了应用服务的镜像制作成本
1.4 容器与虚拟机的比较
- 容器是在操作系统层面上进行虚拟机,直接复用本地主机的操作系统,而传统方式则是在硬件层面实现
- 与传统的虚拟机相比,Docker 优势体现为启动速度快、占用体积小
| 特性 | 容器 | 虚拟机 |
| - | - | - |
| 启动 | 秒级 | 分钟级 |
| 硬盘使用 | 一般为MB
| 一般为GB
|
| 性能 | 接近原生 | 弱于原生 |
| 系统支持量 | 单机支持上千个容器 | 一般几十个 |
2. Docker 组件
2.1 Docker 服务器与客户端
- Docker 是一个客户端-服务器(C/S)架构程序。Docker 客户端只需要向 Docker 服务器或者守护进程发出请求,服务器或者守护进程将完成所有工作并返回结果。Docker 提供了一个命令行工具 Docker 以及一整套 RESTful API。你可以在同一台宿主机上运行 Docker 守护进程和客户端,也可以从本地的 Docker 客户端连接运行在另一台宿主机上的远程 Docker 守护进程
2.2 Docker 镜像与容器
镜像是构建 Docker 的基石。用于基于镜像来运行自己的容器。镜像也是 Docker 生命周期中的“构建”部分。镜像是基于联合文件系统的一种层式结构,由一系列指令一步一步构建出来,例如:
- 添加一个文件
- 执行一个命令
- 打开一个窗口
- 也可以将镜像当作容器的“源代码”。镜像体积很小,非常“便携”,易于分享、存储和更新
Docker 可以帮助你构建和部署容器,你只需要把自己的应用程序或者服务打包放进容器即可。容器是基于镜像启动起来的,容器中可以运行一个或多个进程。我们可以认为,镜像是Docker 生命周期中的构建或者打包阶段,而容器则是启动或者执行阶段。容器基于镜像启动,一旦容器启动完成后,我们就可以登录到容器中安装自己需要的软件或者服务,所以Docker 容器就是:
- 一个镜像格式
- 一些列标准操作
- 一个执行环境
- Docker 借鉴了标准集装箱的概念。标砖集装箱将货物运往世界各地,Docker 将这个模型运用到自己的设计中,唯一不同的是:集装箱运输货物,而Docker 运输软件
- 和集装箱一样,Docker 在执行上述操作时,并不关心容器中到底装了什么,它不管是web服务器,还是数据库,或者是应用程序服务器什么的。所有的容器都按照相同的方式将内容“装载”进去
- Docker 也不关心你要把容器运到何方:我们可以在自己的笔记本中构建容器,上传到Registry,然后下载到一个物理的或者虚拟的服务器来测试,再把容器部署到具体的主机中。就像标准集装箱一样,Docker 容器方便替换,可以叠加,易于分发,并且尽量通用
2.3 Registry(注册中心)
- Docker 用 Registry 来保存用户构建的镜像。Registry 分为公共和私有两种。Docker 公司运营公共的 Registry 叫做 Docker Hub。用户可以在 Docker Hub 注册账号,分享并保存自己的镜像(说明:在Docker Hub 下载镜像很慢,可以自己构建私有的 Registry)
3. Docker 安装
更新 yum
yum update
安装所需的软件包,yum-utils 提供yum-config-manager功能,另外两个是devicemapper驱动依赖的
yum install -y yum-utils device-mapper-persistent-data lvm2
设置 yum 源为阿里云
yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
安装 docker(ce:社区免费版,ee:企业版)
yum -y install docker-ce
查看是否安装成功
docker -v
设置ustc镜像
docker的一些站点都在国外,拉取对应镜像可能速度有点慢/失败,需要将其设置成ustc镜像,能够加快镜像下载的速度,同上面将yum源改为阿里一样
mkdir -p /etc/docker vim /etc/docker/daemon.json
添加如下内容
{ "registry-mirrors": ["https://docker.mirrors.ustc.edu.cn"] }
启动 docker
systemctl start docker
查看是否启动成功
systemctl status docker
查看docker对应信息
docker info
查看 docker 帮助文档
docker --help
停止docker
systemctl stop docker
重启 docker
systemctl restart docker
开机自启动docker
systemctl enable docker
4. 常用命令
4.1 镜像常用命令
4.1.1 查看镜像
docker images
REPOSITORY
:镜像名称TAG
:镜像标签IMAGE ID
:镜像IDCREATED
:镜像的创建日期(不是获取该镜像的日期)SIZE
:镜像大小
这些镜像都是存储在Docker宿主机的
var/lib/docker
目录下
4.1.2 搜索镜像
docker search [名称]
NAME
:镜像名称DESCRIPTION
:镜像的简单描述STARS
:星数,类似于GitHubOFFICIAL
:镜像是否为官方AUTOMATED
:镜像是否由dockerhub自动构建流程创建
4.1.3 拉取镜像
# 不加版本默认为最新版本
docker pull [名称:版本]
4.1.4 删除镜像
# 一般后面跟镜像id,因为id唯一
docker rmi [镜像id/名称]
# 删除所有镜像
docker rmi `docker images -q`
4.2 容器相关命令
4.2.1 查看容器
查看正在运行的容器
docker ps
CONTAINER ID
:容器IDIMAGE
:镜像COMMAND
:命令CREATED
:创建时间STATUS
:状态PORTS
:端口映射NAMES
:容器名称
查看所有容器
docker ps -a
查看最后一次运行的容器
docker ps -l
查看停止的容器
docker ps -f status=exited
4.2.2 创建与启动容器
4.2.2.1 创建容器
创建容器
docker run
-i
:表示运行容器-t
:表示容器启动后会进入其命令行。加入这个两个参数后,容器创建就能登录进去。即分配一个伪终端--name
:为创建的容器命名(名称唯一,重复会报错)-v
:表示目录映射关系(目录挂载)(前者是宿主机目录,后者是映射到宿主机上的目录),可以使用多个-v
做多个目录或文件映射。注意:最好做目录映射,在宿主机上做修改,然后共享到容器上-d
:在run
后面加上-d
参数,则会创建一个守护式容器在后台运行(这样创建容器后不会自动登录容器,如果只加-i
-t
l两个参数,创建后就会自动进去容器)-p
:表示端口映射,前者是宿主机端口,后者是容器内的映射端口。可以使用多个-p
做多个端口映射
交互式方式创建容器
-e
:添加环境变量
# 标签即版本号,如上面的centos:7,如果下载的是最新版本。可省略 # /bin/bash 表示启动后以命令行的方式访问惊醒 docker run -it --name=容器名称 镜像名称:标签 /bin/bash
使用前面下载好的
centos:7
镜像创建容器docker run -it --name=mycentos centos:7 /bin/bash
- 我们使用命令
docker ps
发现会报错,这是因为我们当前终端在容器下,此容器中我们并未安装docker
- 新开一个会话查看一下当前运行的容器
- 退出当前容器
```shell
exit
```
![](https://ucc.alicdn.com/images/user-upload-01/2021062917022175.png)
守护方式创建容器
docker run -id --name=容器名称 镜像名称:标签
同样的,使用之前下载好的
centos:7
镜像创建容器docker run -id --name=mycentos2 centos:7
登录容器
# 守护方式创建容器,登录后再退出,容器还是会在后台运行 docker exec -it 容器名称/id /bin/bash
停止容器
docker stop 容器id/名称
停止后台的
mycentos2
容器docker stop 658f00347e9a
4.2.2.2 启动容器
docker start 容器id/名称
启动刚才停止的容器
docker start 658f00347e9a
4.2.3 文件拷贝
# 将宿主机文件拷贝到容器
docker cp 宿主机文件路径 容器id/名称:容器中文件路径
# 容器中文件拷贝到宿主机
docker cp 容器id/名称:容器中文件路径 宿主机路径
我们随便讲当前目录下的一个文件拷贝到容器的
usr/local
目录下docker cp anaconda-ks.cfg 658f00347e9a:/usr/local
将上面拷贝到容器中的文件再拷贝会宿主机,并修改名称
docker cp mycentos2:/usr/local/anaconda-ks.cfg anaconda-ks2.cfg
4.2.4 目录挂载
- 我们可以在创建容器的时候,将宿主机的目录与容器内的目录进行映射,这样我们就可以通过修改宿主机某个目录的文件从而去影响容器
创建容器 添加
-v
参数,后边为宿主机目录:容器目录docker run -id -v 宿主机目录:容器目录 --name=容器名称 镜像名称:标签
4.2.5 查看容器IP地址
查看容器的各种数据
docker inspect 容器名称/id
直接输出IP地址
docker inspect --format='{{.NetworkSettings.IPAddress}}' 容器名称/id
4.2.6 删除容器
不能删除正在运行的容器,要先停止运行再删除
docker rm 容器名称/id
删除前面创建的
mycentos3
容器docker rm mycentos3
5. 部署应用
5.1 MySQL 部署
拉取MySQL镜像
docker pull mysql:5.7
创建容器
docker run -id --name=mysql -p 3306:3306 -e MYSQL_ROOT_PASSWORD=root mysql:5.7
登录容器
docker exec -it mysql /bin/bash
登录容器MySQL数据库
mysql -uroot -proot --default-character-set=utf8
我的虚拟机的IP地址是
192.168.10.129
,我们远程访问MySQL,可以看到访问成功mysql -uroot -proot -h192.168.10.129 -P3306
注意:这里访问的是宿主机的IP和端口,宿主机映射的端口是哪个就访问哪个端口,比如容器的3306端口在宿主机的映射是33306,那么访问容器的MySQL就是
宿主机IP:33306
5.2 Nginx 部署
拉取nginx镜像
docker pull nginx
创建守护方式容器
docker run -di --name=nginx -p 80:80 nginx
- 通过浏览器访问一下:
192.168.10.129:80
修改nginx配置的话一般通过目录挂载的形式,这里先通过
cp
命令将容器中nginx的配置目录拷贝到宿主机,然后再将宿主机我们之前创建的mydata
目录挂载到容器docker cp nginx:/etc/nginx /usr/local/mydata/nginx/
由于挂载是创建容器时进行的,我这里将当前容器删除再重新创建一个(当前也有其他的方法,我们这里只是练习,简单一点就好)
docker stop nginx docker rm nginx docker run -id --name=nginx -p 80:80 -v /usr/local/mydata/conf/:/etc/nginx nginx
5.3 Redis 部署
拉取redis镜像
docker pull redis
创建redis镜像
docker run -id --name=redis -p 6379:6379 redis
5.4 RabbitMQ 部署
拉入Rabbitmq镜像
docker pull rabbitmq:3.7.12
创建容器
docker run -id --name=rabbitmq -p 5671:5671 -p 5672:5672 -p 4369:4369 -p 25672:25672 -p 15671:15671 -p 15672:15672 rabbitmq:3.7.12
登录
rabbitmq
容器,并安装ui插件docker exec -it rabbitmq /bin/bash rabbitmq-plugins enable rabbitmq_management
- 浏览器访问一下
5.5 Elasticsearch 部署
在Linux上安装7.0版本后,有许多注意的地方,比如
- 不能用root用户启动
- jdk必须是11版本
- 虚拟内存大小等相应的限制
拉取 Elasticsearch 镜像
docker pull elasticsearch:7.5.0
修改虚拟内存区域大小,否则会因为过小而无法启动
sysctl -w vm.max_map_count=262144
创建容器
docker run -id --name=elasticsearch -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" -e "cluster.name=elasticsearch" -v /usr/local/mydata/elasticsearch/plugins:/usr/share/elasticsearch/plugins elasticsearch:7.5.0
安装中文分词器
docker exec -it elasticsearch # 此命令需要在容器中运行 elasticsearch-plugin install https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v7.5.0/elasticsearch-analysis-ik-7.5.0.zip
重启容器
docker restart elasticsearch
- 通过浏览器访问一下
5.6 Zookeeper 部署
拉取 Zookeeper 镜像
docker pull zookeeper:3.4.13
创建容器
docker run -id --name=zookeeper -p 2181:2181 zookeeper:3.4.13
6. 迁移与备份
6.1 容器保存为镜像
docker commit 容器名称/id 新镜像名称
将前面创建的
redis
保存为一个新的镜像docker commit redis myredis
基于新生成的镜像创建一个容器
myredis
docker run -id --name=myredis myredis
6.2 镜像备份
docker save -o 镜像文件 镜像名称
将
myredis
镜像备份成一个文件docker save -o myredis.tar myredis
- 将当前宿主机的
myredis
镜像删除
6.3 镜像恢复与迁移
# -i:输入的文件
docker load -i 镜像文件
将上面生成的镜像文件
myredis.tar
进行恢复docker load -i myredis.tar
我们可以继续创建一个新的
myredis
容器docker run -id --name=myredis myredis
7. Dockerfile 常用命令
7.1 什么是 Dockerfile
Dockerfile 是由一系列命令和参数构成的脚本,这些命令应用与基础镜像(操作级别的镜像,比如:centos镜像)并最终创建一个新的镜像
- 对于开发人员:可以为开发团队提供一个完全一致的开发环境
- 对于测试人员:可以直接拿开发时所构建的镜像或者通过Dockerfile文件构建一个新的镜像开始工作
- 对于运维人员:在部署时,可以实现应用的无缝移植
7.2 常用命令
命令 | 作用 |
---|---|
FROM image_name:tag | 定义了使用哪个基础镜像启动构建流程(基础镜像要存在,若不存在,会优先pull基础镜像) |
MAINTAINER user_name | 声明镜像的创建者(非必须) |
ENV key value | 设置环境变量(可以写多条) |
RUN command | 是 Dockerfile 的核心部分(可以写多条) |
Add source_dir / file dest_dir / file | 将宿主机的文件复制到容器内,如果是一个压缩文件,将会在复制后自动解压 |
COPY source_dir / file dest_dir / file | 和 ADD 相似,但是如果有压缩文件不进行解压 |
WORKDIR path_dir | 设置工作目录 |
7.3 Dockerfile 构建 jdk1.8 镜像
JDK1.8下载路径: http://ruochen.net.cn:8080/JDK/jdk1.8
创建目录
mkdir -p /usr/local/dockerjdk8
将jdk1.8 tar包放入刚新建的文件夹中
mv jdk-8u202-linux-x64.tar.gz /usr/local/dockerjdk8/
编写
Dockerfile
文件vim Dockerfile
FROM centos:7 MAINTAINER ruochen WORKDIR /usr RUN mkdir /usr/local/java ADD jdk-8u202-linux-x64.tar.gz /usr/local/java ENV JAVA_HOME /usr/local/java/jdk1.8.0_202 ENV PATH $JAVA_HOME/bin:$PATH
执行
Dockerfile
构建镜像# .是指当前目录(Dockerfile所在目录) # docker build -t='镜像名称' . docker build -t='jdk1.8' .
8. Docker 私有仓库搭建与配置
8.1 私有仓库搭建与配置
拉取私有仓库镜像
docker pull registry
启动私有仓库容器
docker run -id --name=registry -p 5000:5000 registry
- 打开浏览器访问
http://192.168.10.129:5000/v2/_catalog
看到{"repositories":[]}
表示私有仓库搭建成功并且内容为空
修改
daemon.json
vim /etc/docker/daemon.json
{"insecure-registries":["192.168.10.129:5000"]}
此步骤用于让 docker 信任私有仓库地址
重启 docker 服务
systemctl restart docker
重新运行
registry
容器docker start registry
8.2 Docker 私有仓库镜像上传
- 将前面创建的
jdk1.8
镜像上传到私有仓库 标记此镜像为私有仓库的镜像
docker tag jdk1.8 192.168.10.129:5000/jdk1.8
上传到私有仓库
docker push 192.168.10.129:5000/jdk1.8
我们再回到网址刷新一下,可以看到多了一个
jdk1.8
![](https://ucc.alicdn.com/images/user-upload-01/20210630105314856.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzI5MzM5NDY3,size_16,color_FFFFFF,t_70)