Docker学习笔记
Docker介绍
官网 https://www.docker.com/
文档 https://docs.docker.com/
仓库地址 https://hub.docker.com/
为什么会有Docker
之前我们开发一款应用的时候,开发负责将产品开发出来打包,然后把包给运维,运维负责去部署该应用所需要的环境,然后将应用进行部署。
问题:这种情况下,经常会有的问题,我电脑能运行,但是给运维,运维部署了就是不可运行。
于此同时,还有其他问题,比如:
- 环境不一致问题
- 多用户操作系统下,每个应用程序相互影响(比如端口冲突)
- 活动时候需要弹性扩容,只能人肉运维
- 安装软件成本过高
为了解决这些问题,起初引入了虚拟化技术,但是虚拟机比较重,每个虚拟机都具有一套完整的操作系统。
后面就引出了更轻量化的容器化技术,使用Docker只需要将应用和所需要运行的环境打包成一个镜像,放到Docker仓库,需要部署的时候,下载下来,直接运行即可。
Docker的历史
在2010年,国外一个小公司DotCloud公司做PAAS云计算服务,但是大公司像AWS,AZURE等的崛起,自己公司无竞争力,于是将自己的容器化技术命名为Docker进行商业化运营,刚开始没有引起业界注意,在公司快活不下去的时候,将项目开源到社区。
在2013年,将核心技术Docker开源后。越来越多的人发现Docker的优点,Docker社区逐渐繁荣起来。
虚拟化技术和容器化技术比较
虚拟化
在容器化技术出来之前,为了解决环境不一致的情况,并为了提高系统和硬件资源的利用率,主要使用的是虚拟化技术。虚拟化技术的实现主要依托于Hypervistor虚拟机监控程序。它处于计算机物理层和虚拟机之间,能够有效地管理计算机的物理资源并将这些资源分配给不同虚拟环境。作为软件,Hypervisor可以直接运行在操作系统之上,作为服务器,它也可以直接安装到硬件上。
Hypervisor直接接管物理资源,可以对它们做分区处理,分配给了多个虚拟机使用,而用户在虚拟机中也可以通过它直接和计算机底层交互。当虚拟机运行时,如果用户的程序发出一条硬件指令请求资源,Hypervisor 就会直接将请求传递到物理系统做缓存更改,所有这些操作速度都和本机运行速度几近相同,这种直接运行在物理硬件中的 Hypervisor 即为我们经常听说的 Type1,也称为裸机管理程序(Metal Hypervisor),目前市面上常用的 VMware ESXi、MiscroSoft Hyper-V 和 KVM(Kernel-based Virtual Machine)都基于这类 Hypervisor。
另一种运行于操作系统之上的 Hypervisor 即为 Type2,这种命名方式非常简单粗暴,让人很难忘记,它的处理方式就是使 Hypervisor 不直接与物理层基础,因此也称作托管程序(Hosted Hypervisor),它主要用于面向个体用户,我们经常在本机中安装的 VirtualBox、VMware WorkStation 就属于这种类型。此时,相较于 Type1 ,Type2 显然多了一些延迟。
容器化
容器为应用程序提供了隔离的运行空间,每个容器内都包含一个独享的完整用户环境空间,一个容器内的变动不会影响其他容器的运行环境。容器技术使用一系列的系统级别的机制:
- Linux Namespaces来进行空间隔离。
- 文件系统的挂载点来决定容器可以访问哪些文件。
- CGroups来确定每个容器可以使用多少资源。
- 容器之外共享一个系统内核,当同一个库被多个容器使用时,提升内存的使用效率。
虚拟机和docker比较:
虚拟机 | Docker | |
---|---|---|
隔离策略 | Hypervistor | CGroups |
启动速度 | 慢 | 快 |
大小 | 大几个G | 小kb-MB |
隔离级别 | 操作系统级 | 进程级 |
集群规模 | 上百 | 上万 |
Docker架构图
https://docs.docker.com/get-started/overview/
Docker基本概念
Docker Client
docker客户端,docker提供了标准化的命令和REST API(衍生出很多图形化界面:Rancher...)来执行docker命令。
仓库注册中心Registry
注册中心是存放镜像的仓库repository,分为共有仓库和私有仓库。
- Docker官方中央仓库最全,但是下载速度比较慢 https://hub.docker.com/
- 国内镜像网站 daocloud: http://hub.daocloud.io/
- 私服
通常配置文件在 /etc/docker/daemon.json
需要进行配置以支持访问私服。deamon配置文档
镜像
类似一个模版,通过镜像创建容器服务。一般需要自己创建。创建方式一般有以下几种:
- 根据Dockerfile进行build。(常用)
- 用正在运行中容器Save。
容器
通过镜像创建,独立运行一个或者一组应用。
Docker安装
Docker官方提供的文档还是比较详细的,我们可以根据官方文档给出的说明来进行各个操作系统的安装:
https://docs.docker.com/engine/install/centos/
Ubuntu安装
#使用 -y 参数来避免确认,实现自动化操作
#安装Docker Engine
sudo apt install -y docker.io
#启动docker服务
sudo service docker start
#当前用户加入docker组
sudo usermod -aG docker ${USER}
Centos安装
1. 下载docker安装依赖环境
yum install -y yum-utils device-mapper-persistent-date | vm2
# yum-utils yum安装的工具包
# device-mapper-persistent-date | vm2 安装数据存储的驱动包
2. 设置新的安装源
官网默认是国外的安装源,下载速度会比较慢。因此我们换成阿里源,速度比较快点。
# 阿里源,速度比较快。
yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
3. 更新yum软件包索引
yum makecache fast
4. 安装docker-ce 社区版本
yum -y install docker-ce
5. 启动docker和设置开机自启
# 启动docker服务
systemctl start docker
# 开机自启动
systemctl enable docker
6. 验证
docker version
docker pull hello-world
docker run hello-world
7. 阿里云镜像加速-解决从官方下载镜像慢的问题
用户支付宝扫码登陆阿里云,进入控制台,搜索容器镜像服务,获取自己的镜像加速地址。
Docker卸载
# 卸载依赖
yum remove docker-ce docker-ce-cli containerd.io
# 删除资源
rm -rf /var/lib/docker # docker 的默认工作路径
Docker的基本操作
官网帮助文档:https://docs.docker.com/engine/reference/run/
帮助命令
# 显示docker版本信息
docker version
# 显示docker详细信息
docker info
# 查询docker命令帮助文档
docker --help
# 查看docker某个命令帮助文档,eg:docker images --help
docker command --help
镜像命令
# 拉取镜像,可以带仓库地址,也就是镜像名称绝对路径。默认是最新latest
docker pull 镜像名称[:tag]
# 查看全部镜像
docker images
# 展示出所有镜像ID
docker images -aq
# 删除本地镜像
docker rmi -f imageId
# 删除本地所有镜像
docker rmi -f $(docker images -qa)
# 在中央仓库搜索镜像
docker search 镜像名称
docker search mysql --filter=STARS=3000 # 搜索出Stars大于3000的mysql镜像
# 本地镜像导出
docker save -o 导出路径 imageId
# 加载本地的镜像文件
docker load -i 镜像名称
# 修改镜像名称
docker tag imageId 新镜像名称:版本
容器命令
要想创建容器,必须有镜像。要运行必须先拉取镜像
新建容器并启动
docker run 镜像ID|镜像名称[:tag]
# 创建一个容器并进入
docker run -it -p 宿主机端口:容器端口 --name 容器名称 镜像ID|镜像名称[:tag]
docker run -d -p 宿主机端口:容器端口 --name 容器名称 镜像ID|镜像名称[:tag]
#-d:后台运行容器
#-p:宿主机端口:容器端口,为了映射当前Linux的端口和容器的端口
#--name: 容器名称,指定容器名称
#-it:使用交互方式运行,进入容器查看内容,退出:exit
查看正在运行的容器
# 查看所有运行中容器
docker ps
# 查看所有容器
docker ps -a
# 查看所有容器ID
docker ps -q
# 查看最近创建的n个容器
docker ps -a -n=1
#-a 查看所有容器,包括没有运行的
#-q 查看所有容器的唯一标识
进入到容器内部
# exec进入容器内部 cmd:/bin/bash 进入容器后开启一个新的终端,可以在里面操作
docker exec -it 容器ID cmd
# 进入容器正在执行的终端,不会启动新的进程
docker attach containerID
查看容器日志
docker log -tf --tail n 容器id
#-f 滚动查看日志
#--tail n 查看日志行数
停止容器
docker stop 容器ID
# 停止所有容器
docker stop $(docker ps -qa)
删除容器:删除前必须停止容器
docker rm 容器ID
# 删除所有容器
docker rm $(docker ps -qa)
docker ps -qa | xargs docker rm
启动容器
docker start 容器ID
重启容器
docker restart containerId
杀掉容器
docker kill contailerId
查看正在运行的容器详细信息
docker inspect containerId
# id:容器的完整ID
# created:创建时间
# path:脚本位置
# args:运行的脚本
# state:容器状态信息
# image:来源镜像
# hostconfig:主机配置
# graphDriver:其他配置 ,mounts:挂载
# config:基本配置,env:基本环境变量,cmd:基本命令
# networkSettings:网卡信息
从容器内拷贝文件到主机上
# 进入正在运行的容器
docker attach containerId1
# 拷贝容器文件到主机
docker cp containerID:容器内文件绝对路径 本机路径
查看容器内容占用
docker stats
Docker镜像
容器镜像内部并不是一个平坦的结构,而是由许多的镜像层组成的,每层都是只读不可修改的一组文件,相同的层可以在镜像之间共享,然后多个层像搭积木一样堆叠起来,再使用一种叫“Union FS 联合文件系统”的技术把它们合并在一起,就形成了容器最终看到的文件系统。
在使用 docker pull、docker rmi 等命令操作镜像的时候,输出信息其实就是镜像里的各个Layer。Docker会检查是否有重复的层,如果本地已经存在就不会重复下载,如果层被其他镜像共享就不会删除,这样就可以节约磁盘和网络成本。
通过docker inspect image_id
可以看到镜像层。
联合文件系统
Union FS联合文件系统是一种分层,轻量级并且高性能的文件系统。它支持对文件系统的修改作为一次提交来一层层的叠加,同时可以将不同目录挂载在同一个虚拟文件系统下。union文件系统是docker镜像的基础。镜像可以通过分层来进行集成。基于基础镜像,可以制作各种具体的应用镜像。
BootFS:Boot file system
RootFS:Root file system
Docker镜像分层
Docker下载镜像时,下载的一层层就是联合文件系统,Docker镜像由一层一层的文件系统组成,这种层级的文件系统就是UnionFS。
Docker镜像都是只读的,当容器启动时,一个新的可写层被加到镜像的顶部,这一层就是我们通常说的容器层,容器层之下的都叫镜像层
Docker为什么要分层呢
资源共享,多个镜像都从相同base镜像构建而来,那么宿主机只需在磁盘上保留一份base镜像,同时内存中也只需要加载一份base镜像,这样就可以为所有容器服务,而且镜像的每一层都可以被共享。
# 查看镜像分层的方式:
docker image inspect imageID
提交镜像
我们除了从官方下载镜像,工作中我们也会创建自己的镜像,公司内部上传到公司私服,自己有时会上传到官方仓库。
下面只是提交容器成为一个镜像,后面我们也可以直接使用Dockerfile文件构建我们自己的镜像。
# 提交容器成为一个镜像
docker commit -m="提交的描述信息" -a="作者" 容器id 目标镜像名称:[TAG]
容器数据卷Volume
我们在将应用和环境打包成一个镜像的时候,我们是否有考虑过数据的问题?
- 数据在容器中,容器删除,数据丢失。数据需要持久化
- 共享镜像,但是不想共享某些数据。数据需要隔离
- 多个容器需要共享数据怎么办
- 容器内镜像是阉割版本,操作容器内配置不方便
那么我们可以将容器中的目录挂载到Linux,这样,我们就可以在本机操作容器配置,并且容器间可以共享数据。
容器数据卷就是将宿主机中的一个目录映射到容器的一个目录中,可以在宿主机中操作目录中内容,那么容器内部映射的文件,也会一起改变
创建数据卷
docker volume create 数据卷名称
# 创建一个数据卷之后,默认会存放在一个目录下/var/lib/docker/volumes/数据卷名称/_data
# 刚创建的数据卷没挂载在任何容器上。
查看数据卷详细信息
# 查看数据卷详细信息
docker volume inspect 数据卷名称
# 查看全部数据卷
docker volume ls
# 删除数据卷
docker volume rm 数据卷名称
应用数据卷挂载
具名挂载:有名字的数据卷,具名挂载方便的找到我们使用的一个卷
匿名挂载:默认的数据卷名称,docker自动创建的数据卷名称。
ro read only 只读
rw read write 读写
-v 挂载,当源路径不存在时候,会自动创建。当挂在源路径时,确保源路径里文件存在,若容器有用该文件处理,则会出错。
# -v 主机目录:容器内目录;直接指定一个路径作为数据卷的存放位置(不会把容器内部文件带出来,是一个空目录)
docker run -v 主机目录:容器内目录
# -v 容器内目录
docker run -v 容器内目录 imageID
# -v 卷名:容器内路径;当映射数据卷时候,当数据卷不存在,docker会自动创建到默认位置,(会将容器内部自带的文件,存储在默认的存放路径中)
docker run -v 卷名:容器内路径 imageID
# 可以使用监控命令查看该容器详细信息
docker inspect containerId
数据卷容器
多个容器可以进行数据共享
# 数据卷容器
# 父容器删除,子容器共享的卷不会删除。只要一个容器在使用卷,那么卷就不会删除。
# 容器之间配置信息的传递,容器卷容器的生命周期一直持续到没有容器使用为止。
docker run --volume-from containerId
Dockerfile
Dockerfile是用来构建docker镜像的文件。
官方会提供一些基础的镜像,但是我们有时候需要构建自己的镜像。
eg:
linux中添加自己的工具构建一个镜像
自己的应用构建一个镜像
我们来看下centos的dockerfile文件:
FROM scratch # 不依赖任何基准镜像
ADD centos-8-x86_64.tar.xz /
LABEL org.label-schema.schema-version="1.0" org.label-schema.name="CentOS Base Image" org.label-schema.vendor="CentOS" org.label-schema.license="GPLv2" org.label-schema.build-date="20201204"
CMD ["/bin/bash"]
Dockerfile文件
镜像是样板间的话,那么容器就是根据样板间构建的实际房子。而样板间的制作可以通过图纸来实现,而Dockerfile文件就是镜像的图纸。我们可以通过Dockerfile文件来表述镜像的文件系统,环境变量,启动命令等环境,并根据此生成镜像。
基本规则如下:
- 每个指令都必须大写字母
- 构建时候按照从上往下顺序执行
-
表示注释
- 每一个指令都会创建一个新的镜像层,并提交。
Dockerfile常用命令
FROM #基础镜像 比如centos,scratch不依赖任何基准镜像。
MAINTAINER #镜像维护人员 name<email>
LABEL #标签 version="1.0",describe="....."
ADD #复制文件 eg:ADD hello /
# ADD hello / 复制hello文件到根目录
# ADD test.tar.gz / 添加根目录并解压
# ADD 除了复制,还有添加远程文件功能
COPY #复制文件
WORKDIR #设置镜像的工作目录,eg:/usr/local.工作目录就是运行容器后进入容器直接所在的目录
ENV #设置环境变量,提高程序可维护性。后面可以通过$符号引用。eg:ENV
JAVA_HOME=/usr/local/openjdk8
RUN #在构建镜像时执行,RUN yum install -y vim
CMD #在容器创建时执行的命令,多个命令时,只有最后一个会生效,命令可被替代
ENTRYPOINT #在容器创建时执行的命令,命令不可被替代,只能被追加,最后一个一定会被执行
VOLUME # 挂载目录
EXPOSE # 指定暴露端口,跟-p一样
ONBUILD # 当构建一个被继承Dockerfile 这个时候运行ONBUILD指定,触发指令
CMD和ENTRYPOINT的区别
ENTRYPOINT
在容器启动时执行命令,最后一个一定会被执行
cmd
设置默认执行的命令 多个cmd 只要最后一个被执行
,不一定被执行。被创建容器后指令替代
可以组合使用
ENTRYPOINT [“ps”]
CMD [“-ef”]
利用Dockerfile文件构建镜像
先编写一个简单的Dockerfile文件,实现功能如下:以centos为基础镜像,添加vim命令和网络工具包
FROM centos
MAINTAINER lendea<endeal@gmail.com>
LABEL version="1.0"
LABEL describe="centos带vim和网络工具"
ENV MYPATH /usr/local
WORKDIR $MYPATH
RUN yum -y install vim
RUN yum -y install net-tools
EXPOSE 80
CMD echo $MYPATH
CMD echo "docker file build end..."
CMD /bin/bash
构建命令:
docker build -f dockerfile文件名 -t 镜像名:[TAG] {构建上下文,当前文件目录中为点.}
查看镜像构建历史
# 镜像构建历史
docker history imageID
Docker应用
Mysql安装
docker search mysql
# 拉取
docker pull mysql:5.7
# 挂载
docker run -d -p 3310:3306 -v /home/mysql/conf:/etc/mysql/conf.d -v /home/mysql/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 --name mysql01 mysql5.7
# -d 后台运行
# -p 端口映射
# -v 卷挂载
# -e 环境配置 安装启动mysql需要配置密码
# --name 容器名字