Docker的使用
1 Docker简介
软件开发人员,经常需要安装新的软件,复杂的软件需要安装一大堆依赖,并且对依赖组件的版本还有要求,有时安装一个软件需要半天的时间,实在令人抓狂,所以Docker出现了,docker可以将应用和环境打包成一个容器,随后可以在任何地方运行(简单来说Docker就是软件带环境安装)。
下图是docker的logo,很形象的说明了docker的作用,在同一台物理机上可以装载不同的集装箱(不同程序,即容器),这些集装箱之间相互隔离不影响。正如docker的口号:Build,Ship and Run Any App, Anywhere
2 Docker的整体架构
2.1 Docker 不是虚拟机(VM)
docker诞生就是为了解决开发环境和多软件版本不一致的问题,虚拟机VM也可以解决这个问题,但是虚拟机比较耗资源,从下图可以简单的看出来,docker并不是虚拟机。
docker与虚拟机的区别如下:
-
资源占用不同:
-
虚拟机通过虚拟出整套操作系统虚拟化资源,虚拟机通常需要更多的CPU、内存、存储资源;
-
Docker通过对进程进行隔离来虚拟化应用环境,Docker比较轻量,可以共享宿主机内核,消耗更少资源
-
-
启动速度不同:
- 虚拟机启动一个完整的操作系统非常缓慢,一些系统级别操作步骤,往往无法跳过,比如用户登录;
- Docker只封装应用运行所需最基础的资源,启动容器的速度可以在秒级(相当于启动一个进程)
-
目的不同:
- 虚拟机用于基础设施虚拟化,具有完全隔离的硬件与操作系统
- Docker用于应用级别的轻量化虚拟化,安全性相对较低
注意:由docker架构示意图可以看出,所有容器都共用Host的kernel,在容器中没办法对kernel进行升级,如果容器对kernel版本有要求,则不建议用容器,这种场合使用虚拟机更合适。
2.2 Docker的架构
docker整体架构如下图所示:
Docker的核心组件包括:
- Docker客户端:Client
- Docker服务端:Docker daemon
- Docker镜像: Images
- Docker容器:Containers
- Docker仓库:Registry
详细说明如下:
Client与Docker daemon:
Docker采用的是Client/Server架构,客户端是Client,服务端是Docker daemon,客户端向服务器发送请求,服务端负责构建、运行、分发、存储容器,客户端和服务端可以运行在同一个Host上,也可以运行在不同Host上(通过socket等通信)
Images与Containers
Images即docker镜像,可以看成是只读模板,通过它可以创建Docker容器。
Containers即Docker容器,就是通过Image运行的实例(运行的进程)
Registry
Registry是存放Docker镜像的仓库,用户也可以常见自己私有的Registry
Docker默认的仓库为:https://hub.docker.com/
3 Docker的常用命令
仓库Registry相关指令:
命令 | 含义 |
---|---|
docker [image] pull NAME[:TAG] | 从Docker的一个仓库服务器下拉一个镜像,如果不显式指定TAG,则默认会选择latest标签,这会下载仓库中最新版本的镜像 |
docker [image] push | 将一个镜像推送到Docker的注册服务器上 |
镜像images相关命令:
可以通过下面命令查看:
$ docker image --help
命令 | 含义 |
---|---|
docker images | 列出存在的镜像 |
docker [image] build | 从一个Dockerfile创建一个镜像 |
docker [image] history < name or ID > | 镜像的构建历史 |
docker image rm < name or ID > 或 docker rmi < name or ID > | 删除给定的若干个镜像 |
docker [image] save -o xxx.tar < name or ID > | 将镜像保存为tar包文件 |
docker [image] load -i xxx.tar | 将tar文件再导入到本地镜像库 |
docker [image] tag NAME:TAG NEWNAME:TAG | 为本地镜像任意添加新的标签,只是别名而已 |
容器container 相关命令:
可以通过下面命令查看:
$ docker container --help
命令 | 含义 |
---|---|
docker [container] run < image name > | 基于镜像创建容器,如果系统中没有这个镜像, Docker会自动去Docker Hub上拉取对应的镜像到本地 |
docker [container] commit | 在一个容器中修改后,创建一个新的镜像 |
docker container ls 或: docker ps | 查看这个容器的信息和状态 |
docker [container] start < name or ID > | 启动容器 |
docker [container] stop < name or ID > | 停止容器 |
docker [container] rm < name or ID > | 删除容器 |
docker [container] attach < name or ID > | 连接进入到一个正在运行的容器中,或使用docker exec -it < name or ID > |
docker run常用的几个参数:
# -t选项让Docker分配一个伪终端(pseudo-tty)并绑定到容器的标准输入上
# -i则让容器的标准输入保持打开。
docker run -ti < image name >
# -v <宿主机目录>:<容器目录>,将宿主机上的目录或文件挂载到容器中的指定位置,以实现数据的共享和持久化
# 例如:将宿主机上的/data目录挂载到容器的/app/data目录
docker run -it -v /data:/app/data < image name >
4 Dockerfile
docker镜像有多种生成方法:
- 基于已有镜像创建
- 基于Dockerfile创建
简略描述如下:
1. 基于已有镜像创建:
可通过docker run获取一个简单基础镜像,修改后,重新提交,创建一个新的镜像。
# 1 拉取一个基础镜像
$ sudo docker run -ti ubuntu:20.04
# 2 修改,可以安装各种软件环境等,如安装vim
$ sudo apt install vim
# 3 将容器保存为新的镜像
$ sudo docker commit 容器ID/名称 仓库名称:[标签]
2. 基于Dockerfile创建:
可以通过一个文件来描述创建镜像的步骤,这个文件就是Dockerfile。
指令 | 说明 |
---|---|
FROM | 指定父镜像,如: (基础镜像:FROM scratch,或基于普通镜像:FROM ubuntu:20.04) |
MAINTAINER | 镜像是谁写的 |
RUN | 镜像构建的时候需要运行的命令 |
ADD | 将本地文件添加到容器中,tar类型文件会自动解压(网络压缩资源不会被解压),可以访问网络资源,类似wget |
WORKDIR | 镜像的工作目录,相当于cd命令 |
VOLUME | 挂载的目录 |
EXPOSE | 暴露端口配置 |
CMD | 指定这个容器启动的时候要运行的命令(只有最后一个会生效,可被替代) |
EMTRYPOINT | 指定这个容器启动的时候要运行的命令,可以追加命令 |
ONBUILD | 当构建一个被继承DockerFile,这个时候就会运行ONBUILD的指令,触发指令 |
COPY | 功能类似ADD,但是是不会自动解压文件,也不能访问网络资源 |
ENV | 构建的时候设置环境变量 |
以下是一个简单Dockerfile示例:
FROM ubuntu:20.04 #父镜像
MAINTAINER sureZ
ENV MYPATH /usr/local #环境变量目录
WORKDIR $MYPATH #工作目录
RUN yum -y install vim #执行构建命令 安装vim, -y表示强制安装
RUN yum -y install net-tools #执行构建命令 安装net-tools
EXPOSE 80 #暴露端口 80
CMD echo $MYPATH #输出构建信息 mypath
CMD echo "---end---" #输出信息
CMD /bin/bash #进入/bin/bash命令行
Dockerfile中的非交互模式:
在使用Dockerfile构建镜像时,有时使用apt安装软件包碰到需要用户进行一些确认,这是后build便中断了,这时候就需要设置该变量来以非交互模式使用默认选项以最快速度完成构建。
# 方法1:apt install -y, 表示在需要确认的场景中回应 yes
apt install -y python3
# 方法2:环境变量 DEBIAN_FRONTEND 设置为noninteractive
# 尽量不要用 ENV DEBIAN_FRONTEND=noninteractive 进行全局设置,
# 因为ENV命令在整个容器运行过程中都会生效,所以当你通过BASH和容器进行交互时,如果进行了全局设置那就会出问题
RUN DEBIAN_FRONTEND=noninteractive apt install -y python3
写好Dockerfile后,使用如下命令构建image,构建完成后使用docker images查看一下
docer build -f Dockerfile -t myubuntu:V1.0
5 其它操作
5.1 退出容器Containers
退出容器分两种情况,一是在容器里面,二是在容器外面
容器里:
方式 | 结果 | 再次启动 |
---|---|---|
exit (命令) | 退出后,容器处于exited状态,docker ps 查不到,docker ps -a可以列出 | docker start 容器名/容器ID,然后docker attach |
Ctrl + D (快捷方式) | 退出后,容器处于exited状态,docker ps 查不到,docker ps -a可以列 | docker start 容器名/容器ID,然后docker attach |
先Ctrl + P 再 Ctrl + Q(快捷方式) | 退出后,容器处于后台运行状态,docker ps 可以查到 | docker attach 容器名/容器ID |
容器外:
方式 | 结果 | 再次启动 |
---|---|---|
docker stop 容器名/容器ID | stop后,容器处于exited状态,docker ps 查不到,docker ps -a可以列出 | docker start 容器名/容器ID,然后docker attach |
5.2 批量删除容器Containers
在使用 Docker 过程中,我们会创建许多容器,如果这些容器不再使用,则应该及时删除,否则它们会占用宝贵的资源。
删掉所有处于停止状态的容器:
# Docker 1.13版本以后,可以使用 docker containers prune 命令,删除处于停止状态的容器。
sudo docker container prune
删掉所有容器:
正在运行的容器,是不可以直接删除的,会报错,所以就需要加上-f强制删除。
sudo docker rm `docker ps -aq`
删掉所有未被使用的镜像:
该命令将删除所有未被使用的镜像,包括没有被任何容器引用的镜像。
sudo docker image prune
5.3 发布容器
方式1:打包本地镜像,拷贝到其它宿主机运行
步骤如下:
step1:执行如下命令找到被打包镜像的名字和版本号
doceker images
step2:打包本地镜像
docker save -o 打包名字.tar 镜像名字:版本号
step3:将tar文件拷贝到其它宿主机,load出来
# 1 load
docker load < 打包名字.tar
# 2 查看
docker images
方式2:将本地构建的Docker镜像推送到Docker镜像仓库
step1:登录Docker镜像仓库
$ sudo docker login
执行该命令后会提示输入用户名和密码。
step2:打tag
使用docker tag命令打标签,将本地构建的镜像与仓库中的镜像进行关联
$ sudo docker tag <image-name:tag> <username>/<repository>:<tag>
step3:push镜像
$ sudo docker push <username>/<repository>:<tag>
别人使用时,直接使用docker pull拉取镜像即可使用
注意:在推送镜像前,需要确保已经成功登录Docker镜像仓库,并且已经打好了标签。
参考: