基础篇
Docker的基本组成
- 镜像(Image):只读模板,用来创建Docker容器,一个镜像可以创建很多容器。
- 容器(Container):使用镜像创建出来的运行实例。
- 仓库(Repository):集中存放镜像文件的场所。公开仓库(https://hub.docker.com)。
Docker架构图(入门版)
Docker总体架构图
Docker安装
参考官网文档(https://docs.docker.com/engine/install/centos/#prerequisites)
#1.更新yum软件包索引
yum makecache fast
#2.安装需要的软件包
yum install -y yum-utils
#3.设置stable镜像仓库
yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
#4.防止安装Docker引擎时报错Requires: fuse-overlayfs >= 0.7,将以下内容添加到/etc/yum.repos.d/docker-ce.repo
[centos-extras]
name=Centos extras - $basearch
baseurl=http://mirror.centos.org/centos/7/extras/x86_64
enabled=1
gpgcheck=0
#5.清除缓存中的所有文件并更新yum软件包索引
yum clean all
yum makecache fast
#6.安装Docker引擎
yum install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
#7.启动Docker
systemctl start docker
配置阿里云镜像加速
阿里云开发者平台:https://promotion.aliyun.com/ntms/act/kubernetes.html
docker run执行逻辑
Docker底层原理
Docker 和传统虚拟化方式的不同之处:
- 传统虚拟机技术是虚拟出一套硬件后,在其上运行一个完整操作系统,在该系统上再运行所需应用进程;
- 容器内的应用进程直接运行于宿主的内核,容器内没有自己的内核且也没有进行硬件虚拟。因此容器要比传统虚拟机更为轻便。
- 每个容器之间互相隔离,每个容器有自己的文件系统 ,容器之间进程不会相互影响,能区分计算资源。
为什么Docker会比VM虚拟机快
1. docker有着比虚拟机更少的抽象层
由于docker不需要实现硬件资源虚拟化,运行在docker容器上的程序直接使用的是实际物理机的硬件资源。因此在CPU、内存利用率上docker将会在效率上有明显优势。
2. docker利用的是宿主机的内核,而不需要加载操作系统OS内核
当新建一个容器时,docker不需要像虚拟机一样重新加载一个操作系统内核。进而避免引寻、加载操作系统内核返回等比较费时费资源的过程,当新建一个虚拟机时,虚拟机软件需要加载OS,返回新建的过程是分钟级别的,而docker由于直接利用宿主机的操作系统,则省略了返回过程,因此新建一个docker容器只需要几秒钟。
对比总结
对比项 | Docker容器 | 虚拟机(VM) |
---|---|---|
操作系统 | 与宿主机共享OS | 宿主机OS上运行虚拟机OS |
存储大小 | 镜像小 | 镜像大(vmdk、vdi等) |
性能 | 几乎无额外性能损失 | 操作系统额外的CPU、内存消耗 |
移植性 | 轻便、灵活,适用于Linux | 笨重,与虚拟化技术耦合度高 |
硬件亲和性 | 面向软件开发者 | 面向硬件运维者 |
部署速度 | 快速 | 较慢 |
Docker常用命令
帮助启动类命令
#启动docker
systemctl start docker
#停止docker
systemctl stop docker
#重启docker
systemctl restart docker
#查看docker状态
systemctl status docker
#开机启动
systemctl enable docker
#查看docker概要信息
docker info
#查看docker总体帮助文档
docker --help
#查看docker命令帮助文档
docker 具体命令 --help
镜像命令
#罗列本地镜像
docker images #列出本地主机上的docker镜像
docker images -a #列出本地所有的镜像(含历史映像层)
docker images -q #列出本地主机上的docker镜像id
#查找镜像
docker search [OPTIONS] xx镜像名 #查找xx镜像
#拉取镜像
docker pull 镜像名[:TAG] #下载镜像
#查看镜像/容器/数据卷所占空间
docker system df
#删除镜像
docker rmi 镜像名或id
docker rmi -f 镜像id1 镜像id2 镜像id3 #强制删除多个镜像
docker rmi -f $(docker images -qa) #强制删除全部镜像
#虚悬镜像:仓库名、标签都是<none>的镜像俗称虚悬镜像(dangling image)
容器命令
常用命令
#列出容器
docker ps [OPTIONS]
docker ps #列出运行中的容器
OPTIONS:
-a,--all 列出全部容器(正在运行+历史运行过的容器)
-l 显示最近创建的容器
-n 显示n个最近创建的容器
-q 只显示容器id
#新建+启动容器
docker run [OPTIONS] IMAGE [COMMAND] [ARG...]
OPTIONS说明(常用):
--name=容器名称 为容器指定一个名称(docker run -it --name=u01 ubuntu bash)--name=u01和--name u01等效
-d 后台运行容器并返回容器id,也即启动守护式容器
-i 以交互模式运行容器,通常与-t同时使用
-t 为容器重新分配一个伪终端,通常与-i同时使用
-P 随机端口映射,大写P
-p 指定端口映射,小写p(hostPort:containerPort -p 8080:80)或(ip:hostPort:containerPort -p 10.0.0.1:8080:80)
#退出容器
exit run进去容器,exit退出,容器停止
ctrl+p+q run进去容器,ctrl+p+q退出,容器不停止
#启动已停止运行的容器
docker start 容器id或容器名
#重启容器
docker restart 容器id或容器名
#停止容器
docker stop 容器id或容器名
#强制停止容器
docker kill 容器id或容器名
#删除容器
docker rm 容器id或容器名 #删除已停止的容器
docker rm -f 容器id或容器名 #强制删除容器(运行中或停止的)
docker rm -f $(docker ps -aq) #删除所有容器
docker ps -aq | xargs docker rm -f #删除所有容器
#查看容器日志
docker logs 容器id或容器名
#查看容器内运行的进程(类似linux中top命令)
docker top 容器id或容器名
#查看容器内部细节
docker inspect 容器id或容器名
进入正在运行的容器并以命令行交互
docker exec -it 容器id或容器名 bashShell
docker attach 容器id或容器名
exec和attach的区别
attach直接进入容器启动命令的终端,不会启动新的进程,用exit退出会导致容器停止。
exec是在容器并打开新的终端,并且可以启动新的进程,用exit退出不会导致容器停止。
启动守护式容器(后台服务器)
docker run -d redis
注意:使用镜像centos以后台模式启动一个容器 docker run -d centos
然后docker ps -a 进行查看,会发现刚启动的容器已经退出
原因:容器运行的命令如果不是那些一直挂起的命令(比如top,tail等),就会自动退出。
所以docker容器要后台运行,就必须有一个前台进程。
容器和主机之间拷贝文件
docker cp [OPTIONS] CONTAINER:SRC_PATH DEST_PATH|-
docker cp [OPTIONS] SRC_PATH|- CONTAINER:DEST_PATH
使用'-'作为目的地,将容器源的tar存档传输到标准输出。
示例: docker cp 83e3d823369a:/root/abc.tar -
使用'-'作为源,从stdin读取tar存档,并将其解压缩到容器中的目标目录。
示例: cat abc.tar | docker cp - 83e3d823369a:/root
导出容器和创建容器镜像
docker export [OPTIONS] CONTAINER 导出容器为归档文件
下面两条命令等效
docker export -o abc.tar 容器id或容器名
docker export 容器id或容器名 > abc.tar
docker import [OPTIONS] file|URL|- [REPOSITORY[:TAG]] 从tar包中导入内容以创建文件系统镜像
下面两条命令等效
docker import abc.tar zjc/ubuntu1.0
cat abc.tar | docker import - zjc/ubuntu1.0
进阶篇
Docker镜像
简介
- 镜像是一种轻量级、可执行的独立软件包,它包含运行某个软件所需的所有内容,我们把应用程序和配置依赖打包成一个可交付的运行环境(包括代码、运行时库、环境变量和配置文件等),这个打包好的运行环境就是image镜像文件。
- Docker的镜像是分层的
联合文件系统UnionFS
- UnionFS(联合文件系统)是一种分层、轻量级并且高性能的文件系统,它支持对文件系统的修改作为一次提交来一层层的叠加,同时可以将不同目录挂载到同一个虚拟文件系统下。
- UnionFS是Docker镜像的基础。镜像可以通过分层来进行继承,基于基础镜像(没有父镜像),可以制作各种具体的应用镜像。
- 特性:一次同时加载多个文件系统,但从外面看起来,只能看到一个文件系统,联合加载会把各层文件系统叠加起来,这样最终的文件系统会包含所有底层的文件和目录。
Docker镜像加载原理
- docker的镜像实际上由一层一层的文件系统组成,这种层级的文件系统UnionFS。
- bootfs(boot file system)主要包含bootloader和kernel, bootloader主要是引导加载kernel, Linux刚启动时会加载bootfs文件系统,在Docker镜像的最底层是bootfs。这一层与我们典型的Linux/Unix系统是一样的,包含boot加载器和内核。当boot加载完成之后整个内核就都在内存中了,此时内存的使用权已由bootfs转交给内核,此时系统也会卸载bootfs。
- rootfs (root fle system),在bootfs之上。包含的就是典型Linux系统中的/dev,/proc, /bin, /etc等标准目录和文件。rootfs就是各种不同的操作系统发行版,比如Ubuntu ,Centos等等。
- docker镜像层都是只读的,容器层是可写的
当容器启动时,一个新的可写层被加载到镜像的顶部。这一层通常被称为“容器层”,“容器层”之下的都叫“镜像层”。
所以对容器的改动(添加、删除、修改文件等)都只会发生在容器层中。
为什么Docker镜像要采用这种分层结构
镜像分层最大的好处就是资源共享,方便复制迁移,就是为了复用。
比如说有多个镜像都是从相同的base镜像构建而来,那么Docker Host只需在磁盘上保存一份base镜像;同时内存中也只需加载一份base镜像,就可以为所有容器服务了。而且镜像的每一层都可以被共享。
扩展镜像(commit操作)
Usage: docker commit [OPTIONS] CONTAINER [REPOSITORY[:TAG]]
Create a new image from a container's changes
Options:
-a, --author string Author (e.g., "John Hannibal Smith <hannibal@a-team.com>")
-c, --change list Apply Dockerfile instruction to the created image
-m, --message string Commit message
-p, --pause Pause container during commit (default true)
- 示例:
docker commit -m="安装了vim" -a="zjc" 容器id或容器名 要创建的目标镜像名:[标签]
或docker commit -m "安装了vim" -a "zjc" 容器id或容器名 要创建的目标镜像名:[标签]
- 小总结
docker中的镜像分层,支持通过扩展现有镜像,创建新的镜像。
新镜像是从base镜像一层一层叠加生成的。每安装一个软件,就在现有镜像的基础上增加一层。
容器数据卷(docker run -v选项)
是什么
- 卷就是目录或文件,存在于一个或多个容器中,由docker挂载到容器,但不属于联合文件系统,因此能够绕过Union File System提供一些用于持续存储或共享数据的特性。
- 卷的设计目的就是数据的持久化,完全独立于容器的生存周期,因此docker不会在容器删除时删除其挂载的数据卷。
- 容器数据卷就是将docker容器内的数据保存到宿主机的磁盘中
能干嘛
- 将docker容器产生的数据持久化
- 特点:
1.数据卷可在容器之间共享或重用数据
2.卷中的更改实时生效
3.数据卷中的更改不会包含在镜像的更新中
4.数据卷的生命周期一直持续到没有容器使用它为止
权限的坑
在SELinux里面docker挂载目录被禁止掉了,如果要开启,一般使用–privileged=true参数为这个容器提供扩展权限来解决挂载目录没有权限的问题,也即使用该参数,container内的root用户拥有真正的root权限,否则container内的root用户只有外部的普通用户权限。
案例
- 宿主机和容器之间映射添加容器数据卷
docker run -it --privileged=true -v /tmp/host_data1:/tmp/docker_data1 -v /tmp/host_data2:/tmp/docker_data2 --name=u1 ubuntu
#查看卷映射规则
docker inspect u1
- 读写规则映射添加说明
- 读写(没有添加读写规则默认是rw可读写)
下面命令和上面的案例等效
docker run -it --privileged=true -v /tmp/host_data1:/tmp/docker_data1:rw -v /tmp/host_data2:/tmp/docker_data2:rw --name=u1 ubuntu
- 只读(容器内只读)
docker run -it --privileged=true -v /tmp/host_data1:/tmp/docker_data1:ro --name=u1 ubuntu
- 读写(没有添加读写规则默认是rw可读写)
- 卷的继承和共享
- 容器1完成和宿主机的卷映射
docker run -it --privileged=true -v /tmp/host_data1:/tmp/docker_data1 --name=u1 ubuntu
- 容器2继承容器1的卷规则
docker run -it --privileged=true --volumes-from u1 --name=u2 ubuntu
查看卷映射规则
docker inspect u2
- 容器1完成和宿主机的卷映射
本地镜像发布到阿里云
本地镜像发布到阿里云流程
将本地镜像推送到阿里云
- 阿里云开发者平台:https://promotion.aliyun.com/ntms/act/kubernetes.html
- 创建仓库镜像
(1). 选择控制台,进入容器镜像服务
(2). 选择个人实例
(3). 命名空间
(4). 镜像仓库
(5). 进入管理界面获得脚本
#1.登录阿里云Docker Registry
docker login --username=aly_zjc888 registry.cn-hangzhou.aliyuncs.com
#2.使用"docker tag"命令重命名镜像,并将它通过专有网络地址推送至Registry
docker tag [ImageId] registry.cn-hangzhou.aliyuncs.com/zjc1/docker-zjc1:[镜像版本号]
#3.使用 "docker push" 命令将该镜像推送至远程
docker push registry.cn-hangzhou.aliyuncs.com/zjc1/docker-zjc1:[镜像版本号]
本地镜像发布到私有库
- 下载镜像docker registry
docker pull registry
- 运行镜像registry,相当于本地有个私有Docker hub
docker run -d -p 5000:5000 --privileged=true -v /dockerHub:/tmp/registry registry
- curl验证私服库上有什么镜像
curl -XGET http://127.0.0.1:5000/v2/_catalog
- 将镜像zjc/ubuntu1.1修改符合私服库规范的TAG
docker tag zjc/ubuntu1.1 127.0.0.1:5000/zjc/ubuntu1.1
- 修改配置文件使之支持http
docker默认不允许http方式推送镜像,通过配置选项来取消这个限制。(修改完后如果不生效,重启docker)
vi /etc/docker/daemon.json
{
“registry-mirrors”: [“https://v0l3see8.mirror.aliyuncs.com”],
“insecure-registries”:[“192.168.80.13:5000”]
}
第一行是阿里云的镜像加速
第二行是允许http方式推送镜像 - push推送到私服库
docker push 127.0.0.1:5000/zjc/ubuntu1.1
- curl验证私服库上有什么镜像
curl -XGET http://127.0.0.1:5000/v2/_catalog
- 拉取刚推送到本地的镜像
docker pull 127.0.0.1:5000/zjc/ubuntu1.1
高级篇
Dockerfile
是什么
- DockerFile是用来构建Docker镜像的文本文件,是由一条条构建镜像所需的指令和参数构成的脚本。
- 官网:https://docs.docker.com/engine/reference/builder/
- 构建三步骤
- 编写Dockerfile文件
- docker build命令构建镜像
- docker run运行容器实例
Dockerfile构建过程解析
Dockerfile内容基础知识
- 每条保留字指令都必须为大写字母且后面要跟随至少一个参数
- 指令按照从上到下顺序执行
- #表示注释
- 每条指令都会创建一个新的镜像层并对镜像进行提交
Docker执行Dockerfile的大致流程
- docker从基础镜像运行一个容器
- 执行一条指令并对容器做出修改
- 执行类似docker commit的操作提交一个新的镜像层
- docker再基于刚提交的镜像运行一个新容器
- 执行Dockerfile中的下一条指令直到所有指令都执行完成
Dockerfile、docker镜像和docker容器关系
Dockerfile常用保留字指令
参考tomcat8的Dockerfile: https://github.com/docker-library/tomcat/blob/master/8.5/jdk8/corretto-al2/Dockerfile
FROM
基础镜像,当前新镜像是基于哪个镜像的,指定一个已经存在的镜像作为模板,有效的Dockerfile必须以FROM指令开始
MAINTAINER
镜像维护者的姓名和邮箱
RUN
构建(build)镜像时需要运行的命令(在docker build时运行)
两种格式
- shell格式: RUN <命令行命令> 命令行命令等同于在终端操作的shell命令
例如:RUN yum -y install vim
- exec格式: RUN [“可执行文件”,“参数1”,“参数2”]
例如:RUN ["./test.php","dev","offline"]
等价于RUN ./test.php dev offline
EXPOSE
当前容器对外暴露的端口
WORKDIR
指定在容器创建后,终端登录进来默认的工作目录
USER
指定该镜像以什么用户执行,如果不指定,默认是root
ENV
用来在构建工程中设置的环境变量
ADD
将宿主机的文件拷贝到镜像且会自动处理URL和解压缩,相当于COPY+解压
COPY
拷贝文件到镜像
VOLUME
容器数据卷,持久化数据
CMD
指定容器启动后要干的事情
CMD <容器启动命令>
CMD指令的格式和RUN相似,也有两种格式:
- shell格式:
CMD <命令>
- exec格式:
CMD ["可执行文件","参数1","参数2"...]
- 参数列表格式:CMD [“参数1”,“参数2”…],在指定了ENTRYPOINT指令后,用CMD指定具体的参数
- 注意:
- Dockerfile中可以有多个CMD指令,但只有最后一个生效,CMD会被docker run之后的参数覆盖
- CMD和RUN指令的区别:
CMD是在docker run时运行
RUN是在docker build时运行
ENTRYPOINT
-
指定容器启动后要干的事情,类似于CMD指令,但是ENTRYPOINT不会被docker run后面的参数覆盖,而且这些命令行参数会被当作参数传递给ENTRYPOINT指令指定的程序
-
指令格式:
ENTRYPOINT ["可执行文件","参数1","参数2"...]
-
ENTRYPOINT可以和CMD一起用,一般有变参才会使用CMD,这时CMD等于给ENTRYPOINT传参。
-
案例:假设构建nginx:test镜像的Dockerfile如下
FROM nginx
ENTRYPOINT [“nginx”,“-c”] #定参
CMD [“/etc/nginx/nginx.conf”] #变参按照Dockerfile编写执行 传参运行 docker命令 docker run nginx:test docker run nginx:test -c /etc/nginx/new.conf 实际执行命令 nginx -c /etc/nginx/nginx.conf nginx -c /etc/nginx/new.conf
小总结
build | both | run |
---|---|---|
FROM | WORKDIR | CMD |
MAINTAINER | USER | ENV |
COPY | EXPOSE | |
ADD | VOLUME | |
RUN | ENTRYPOINT | |
ONBUILD | ||
.dockerignore |
案例
自定义镜像mycentosjava8
- 要求
CentOS7镜像具备vim+ifconfig+jdk8
JDK的下载地址:
官网:https://www.oracle.com/java/technologies/downloads/#java8
其他:https://mirrors.yangxingzhen.com/jdk/ - 编写Dockerfile
vim Dockerfile
FROM centos:centos7.9.2009
MAINTAINER ZJC<1580739389@qq.com>
ENV MYPATH /usr/local
WORKDIR $MYPATH
#安装vim编辑器
RUN yum -y install vim
#安装ifconfig命令
RUN yum -y install net-tools
#安装java8及lib库
RUN yum -y install glibc.i686
RUN mkdir /usr/local/java
#把jdk-8u192-linux-x64.tar.gz添加到镜像中
ADD jdk-8u192-linux-x64.tar.gz /usr/local/java/
#配置java环境变量
ENV JAVA_HOME /usr/local/java/jdk1.8.0_192
ENV JRE_HOME $JAVA_HOME/jre
ENV CLASSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar:$JAR_HOME/lib:$CLASSPATH
ENV PATH $JAVA_HOME/bin:$PATH
CMD echo $MYPATH
CMD echo "success-----------ok"
CMD /bin/bash
- 构建(docker build -t 新镜像名字:TAG .)
docker build -t mycentosjava8:1.0 .
虚悬镜像
- 是什么
仓库名、标签都是<none>的镜像俗称虚悬镜像(dangling image) - 写一个
vim Dockerfile
FROM ubuntu
CMD "success"
- 构建一个虚悬镜像
docker build .
- 查看
docker image ls -f dangling=true
- 删除
虚悬镜像已经失去了存在的价值,可以删除
docker image prune
Docker网络
#docker网络命令用法
docker network --help
#使用自定义的网络zjc_network启动容器tomcat81
docker run -d -p 8081:8080 --network zjc_network --name tomcat81 tomcat8-jdk8