安装
安装步骤可以直接参考官方文档:
- CentOS https://docs.docker.com/engine/install/centos/
- Ubuntu https://docs.docker.com/engine/install/ubuntu/
- Windows(10+)https://docs.docker.com/desktop/windows/install/
镜像加速
从 Docker Hub 上拉取镜像可能会比较慢,可以使用国内的一些镜像加速器服务:
- 阿里云: 需要自行注册获取地址,点击管理控制台 -> 登录账号 -> 右侧镜像工具 -> 镜像加速器 -> 复制加速器地址
- 百度云:https://mirror.baidubce.com
- 网易云:https://hub-mirror.c.163.com
CentOS、Ubuntu 可以在/etc/docker/daemon.json
中配置镜像加速器:
{
"registry-mirrors": [
"https://hub-mirror.c.163.com",
"https://mirror.baidubce.com"
]
}
Windows 则可以在Settings -> Docker Engine -> 右侧 JSON
中配置上边的内容。
优势
传统的虚拟机需要实现硬件资源的虚拟化,而 Docker 直接使用物理机上的硬件资源;新建一个容器时不需要像虚拟机那样重新加载一个操作系统内核,而直接使用宿主机的操作系统内核;因此 Docker 更加的轻量级、运行效率更高!
启停命令
CentOS 下 一些 Docker 常用的启停命令:
- 启动:
systemctl start docker
- 停止:
systemctl stop docker
- 重启:
systemctl restart docker
- 开机启动:
systemctl enable docker
- 查看状态:
systemctl status docker
镜像(Image)
Docker 中的镜像是一个特殊的分层文件系统,主要提供容器运行时所需的程序、库、资源、配置等文件外,还包含了一些为运行时准备的一些配置参数(如匿名卷、环境变量、用户等)。镜像不包含任何动态数据,是只读的,其内容在构建之后也不会被改变。
Docker 在设计镜像时,利用 Union FS(联合文件系统)技术,将其设计为分层存储的架构,分层存储的特点使得镜像复用、定制变的更为容易。可以用现有的镜像为基础层,来添加新的层,以定制自己所需的内容。镜像是逐层构建的,前一层是后一层的基础,每一层构建完就不会再发生改变。
https://docs.docker.com/engine/reference/commandline/image/
列出已下载的镜像:
docker image ls、docker images
只列出镜像 id:
docker image ls -q
-
拉取镜像:
docker pull [镜像仓库地址] 仓库名[:标签]
- 镜像仓库地址默认是
Docker Hub(docker.io)
- 仓库名由
用户名/软件名
组成,对于 Docker Hub 如果不指定用户名默认是library
,也就是官方镜像
- 镜像仓库地址默认是
搜索镜像:
docker search 仓库名:标签
查看镜像、容器、数据卷、缓存占用的空间:
docker system df
删除指定镜像:
docker image rm 仓库名[:标签]/镜像id
删除无用镜像:
docker image prune
-
保存、加载镜像:
-
docker save 仓库名[:标签]/镜像ID > 文件名.tar
,将镜像保存为文件,会保存该镜像的的所有历史记录 -
docker load 文件名.tar
,从文件加载镜像,会恢复镜像名、标签等信息
-
-
制作镜像:
docker commit [OPTIONS] CONTAINER [REPOSITORY[:TAG]]
,将容器保存为镜像- OPTIONS 可以指定
-a
(作者信息);-m
(提交信息) - CONTAINER 可以是容器名、容器ID
- [REPOSITORY[:TAG]],生成镜像的名字、版本等
- 最终的镜像会添加大量无关内容,导致镜像体积大;外界无法知道镜像的制作过程,执行了那些命令;所以一般不会使用该命令制作镜像,而是使用
Dockerfile
。
- OPTIONS 可以指定
容器(Container)
镜像和容器的关系,类似面向对象程序设计中的类和实例,镜像是静态的定义,容器是镜像运行时的实体。容器可以被创建、启动、停止、删除、暂停等。
容器的本质进程,它运行在自己的独立的命名空间。容器可以拥有自己的文件系统、网络配置、进程空间等,可以看做是一个简易的 Linux 环境。容器内的进程是运行在一个隔离的环境里,使用起来,就好像是在一个独立于宿主的系统下操作一样。这种特性使得容器封装的应用比直接在宿主运行更加安全。也因为这种隔离的特性,很多人初学 Docker 时常常会混淆容器和虚拟机。
容器运行时,会以镜像为基础层,在其上创建一个当前容器的运行时需要的存储层,容器存储层的生命周期和容器一样,任何保存于容器存储层的信息都会随容器删除而丢失。
根据 Docker 的最佳实践,容器不应该向其存储层内写入任何数据,容器存储层要保持无状态化。所有的文件写入操作,都应该使用数据卷(Volume)
或者绑定宿主目录
,其性能和稳定性更高。数据卷的生命周期独立于容器,因此容器删除或者重新运行之后,数据却不会丢失。
https://docs.docker.com/engine/reference/commandline/container/
- 启动容器:
docker run [OPTIONS] IMAGE [COMMAND] [ARG...]
,OPTIONS 常用的参数如下:-
--name="容器名"
,给容器指定一个名称,不指定则随机分配 -
-d
,在后台运行容器、并返回容器 ID,也称作守护状态运行 -
-i
,以交互模式运行容器,通常和 -t 一起使用 -
-t
,给容器重新分配一个伪输入终端,通常和 -i 一起使用 -
-P/-p
,指定端口映射,详细内容见网络部分
-
使用 ubuntu 镜像以交互模式启动一个容器,并在容器内执行 /bin/bash 命令,得到一个交互式终端,退出终端可以使用exit
:
docker run -it ubuntu:18.04 /bin/bash
-
列出指定容器:
docker ps [OPTIONS]
,OPTIONS 常用的参数如下:-
-a
,列出当前所有运行的容器、历史上运行过的容器 -
-l
,列出最近创建的容器 -
-n
,列出最近创建的 n 个容器 -
-q
,可以上前几个参数配合使用,只显示容器编号
-
-
退出容器:在容器的交互模式下,退出终端
-
exit
,会停止容器的运行 -
ctrl + q + p
,不会停止容器
-
停止容器:
docker stop 容器ID/容器名
启动停止运行的容器:
docker start 容器ID/容器名
重启容器:
docker restart 容器ID/容器名
强制停止容器:
docker kill 容器ID/容器名
删除停止运行的容器:
docker rm 容器ID/容器名
,删除运行中的容器需要添加-f
查看容器日志:
docker logs -f 容器ID/容器名
-
进入容器:使用 -d 参数启动的后台运行容器,使用如下命令可进入交互终端:
-
docker attach 容器ID/容器名
,执行exit
会导致容器停止 -
docker exec -it 容器ID/容器名 /bin/bash
,执行exit
不会停止容器
-
容器内拷贝文件到宿主机:
docker cp 容器ID:容器内路径 目标主机路径
,反过来拷贝也是类似的-
导入、导出容器快照:
-
docker export 容器ID/容器名 > 文件名.tar
,导出容器快照(容器文件系统)到指定文件,会丢失所有元数据和历史记录,仅保存容器当时的状态 -
cat 文件名.tar | docker import - 用户名/镜像名:镜像版本号
,从容器快照文件导入新镜像,可以指定镜像名、标签等信息 -
docker import URL
,从 URL 导入镜像
-
数据存储
默认情况下,容器内产生的数据存储在其内部的可写层,其它进程很难访问这些数据,或者将其移动到其它地方,而且数据会随着容器的删除而丢失。容器内的可写存储层需要的存储驱动使用了联合文件系统,相比直接将数据存在主机目录性能也会差一些。
https://docs.docker.com/storage/
Docker 提供了如下两种方式将容器数据存储到宿主机上,也称作目录挂载:
-
Volumes
,数据卷,将容器数据存储到由 Docker 管理的宿主机目录中(Linux 上是 /var/lib/docker/volumes/),它和宿主机的核心功能隔离,一个数据卷可以挂载到多个容器,实现容器间数据共享,这也是 Docker 推荐的方式。挂载时只需要指定数据卷的名称,适合挂载数据库等。
docker run -d -p 8008:80 --name web -v nginx:/usr/share/nginx/html nginx
通过-v
命令将名为nginx
的数据卷挂载到容器的/usr/share/nginx/html
目录,如果数据卷不存在则会隐式创建,也可以显示创建,docker volume create xxx
。此时如果数据卷为空则挂载到的容器目录中的数据会被复制到数据卷中;如果数据卷不为空则数据卷中的数据会覆盖容器目录的数据。我们可以根据需要配置多组-v
命令。
也可以使用--mount
命令,但如果数据卷不存在会报错。
-
Bind mounts
,可以将数据存储在宿主机上的任意目录,挂载时需要指定宿主机上目录的绝对路径,也可以挂载到多个容器上,适合挂载配置文件等。
docker run -d -p 8008:80 --name web -v /opt/software/nginx:/usr/share/nginx/html nginx
同样使用-v
命令,这里需要指定宿主机目录的绝对路径,如果目录不存在会自动创建;注意,宿主机目录的数据会直接覆盖容器目录的数据,这里和数据卷是有区别的。这里也可以使用--mount
指令。
Dockerfile
Dockerfile 是用来构建 Docker 镜像的文本文件,其中包含了一条条的指令,每一条指令(指令的内容描述了该层应当如何构建)会构建镜像的一层。
https://docs.docker.com/engine/reference/builder/
Dockerfile 指令:
-
FROM
,指定基础镜像,FROM 是必需的指令,并且必须是第一条指令;除了指定现有镜像为基础镜像外,还可以指定名为scratch
的特殊镜像,它表示不以任何镜像为基础,接下来所写的指令将作为镜像第一层开始存在 -
RUN
,用来执行命令行命令,通常用于安装应用和软件包,有两种格式:- shell 格式:RUN <命令>,类似直接在命令行输入命令,推荐使用该格式
- exec 格式:RUN ["可执行文件", "参数1", "参数2"],类似函数调用的形式
-
EXPOSE
,容器运行时对外暴露的端口,格式为EXPOSE <端口1> [<端口2>...]
,就是-p <宿主端口>:<容器端口>
中的容器端口 -
WORKDIR
,指定容器创建后,终端登录进来的默认工作目录,不存在会自动创建,格式为WORKDIR <工作目录路径>
-
USER
,指定以什么样的用户身份去执行镜像,默认是 ROOT 用户,格式为USER <用户名>[:<用户组>]
-
ENV
,设置环境变量,可以在其它指令中使用($key),格式为ENV <key> <value>
或者ENV <key>=<value>
-
VOLUME
,定义匿名数据卷,防止运行时用户忘记将需要的文件目录挂载为数据卷,当然运行容器时也可以覆盖这个挂载设置 -
COPY
,将宿主机下的文件拷贝到镜像,使用 COPY 指令,源文件的各种元数据都会保留,比如读、写、执行权限、文件变更时间等。有两种格式(--chown=<user>:<group> 选项来改变文件的所属用户及所属组):- COPY [--chown=<user>:<group>] <源路径>... <目标路径>
- COPY [--chown=<user>:<group>] ["<源路径1>",... "<目标路径>"]
-
ADD
,将宿主机下的文件拷贝到镜像,会自动下载 URL、解压 tar 压缩包,格式和 COPY 指令基本一样 -
CMD
,指定容器主进程的启动程序、参数,注意,执行 docker run 时镜像名/ID 后的命令会替换 CMD 的配置,CMD 有两种格式:- shell 格式:CMD <命令>
- exec 格式:CMD ["可执行文件", "参数1", "参数2"...],推荐使用该格式
-
ENTRYPOINT
,作用和 CMD 一样,都是指定容器主进程的启动程序、参数,但是执行 docker run 时镜像名/ID 后面的命令不会覆盖掉 ENTRYPOINT 配置的内容,而且后面的命令会作为参数传递给 ENTRYPOINT 指定的启动程序- ENTRYPOINT 也有 shell 和 exec 两种格式,和 CMD 类似
- 如果 ENTRYPOINT 需要指定变化的参数,可以结合 CMD 一起使用,此时 CMD 的作用发生了变化不再是运行启动程序,而是将 CMD 的内容作为动态参数传递给 ENTRYPOINT
FROM centos
ENV MYPATH /usr/local
WORKDIR $MYPATH
# CentOS 8停止更新后,使用yum安装程序的时候会报错,需要做如下修改
RUN cd /etc/yum.repos.d/ \
&& sed -i 's/mirrorlist/#mirrorlist/g' /etc/yum.repos.d/CentOS-* \
&& sed -i 's|#baseurl=http://mirror.centos.org|baseurl=http://vault.centos.org|g' /etc/yum.repos.d/CentOS-* \
&& wget -O /etc/yum.repos.d/CentOS-Base.repo https://mirrors.aliyun.com/repo/Centos-vault-8.5.2111.repo \
&& yum clean all \
&& yum makecache
# 安装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
ADD jdk-8u301-linux-x64.tar.gz /usr/local/java
# 配置java环境变量
ENV JAVA_HOME /usr/local/java/jdk1.8.0_301
ENV JRE_HOME $JAVA_HOME/jre
ENV CLASSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar:$JRE_HOME/lib:$CLASSPATH
ENV PATH $JAVA_HOME/bin:$PATH
EXPOSR 8081
CMD echo $MYPATH
CMD echo "---------success----------"
CMD /bin/bash
构建镜像
一般我们会创建一个名为Dockerfile
的文件,然后通过上边的指令编写构建镜像的脚本,最后通过如下命令完成就像的构建:
docker build -t 镜像名:TAG .
注意命令最后边有一个.
符号,表示执行指令的当前目录,也就是上下文目录
,docker build 命令会将该目录下的内容打包交给 Docker 引擎以帮助构建镜像。
默认情况下,如果不额外指定 Dockerfile 文件的话,会将上下文目录下的名为 Dockerfile 的文件作为 Dockerfile,当然也可以用-f ../Dockerfile.txt
参数指定 Dockerfile 的文件名以及相对上下文路径的存放目录。
一般来说,应该将 Dockerfile 文件放在一个空目录下或者项目根目录下。如果该目录下没有所需文件,那么应该把所需文件复制一份过来。如果目录下有些文件不希望构建时上传给 Docker 引擎,那么可以用 .gitignore 一样的语法写一个.dockerignore
文件来忽略掉它们。
网络
外部访问容器
要从外部访问容器内运行的网络应用时,可以通过 -P 或 -p 参数来指定端口映射:
-
-P
,Docker 会随机映射一个可用的宿主机端口到内部容器开放的网络端口 -
-p
,指定需要映射的端口,一个指定端口上只可以绑定一个容器。支持的格有:-
hostPort:containerPort
,映射到本地的指定端口 -
ip:hostPort:containerPort
,映射到指定地址的指定端口 -
ip::containerPort
,映射到指定地址的任意端口
-
-
docker port <container name/id> containerPort
,查看指定容器端口映射的外部端口配置
容器互联
-
docker network create [-d 网络类型] <name>
,创建网络,网络类型默认为bridge
-
docker network ls
,查看已有网络 -
docker network rm <name/NETWORK ID>
,删除指定网络
我们可以创建一个网络,然后在运行容器时使用--network
指定要连接到的网络,这样不同容器可以运行在同一网络,实现容器间的互联:
docker network create -d bridge net007
docker run -d -p 8008:80 --name web -v nginx:/usr/share/nginx/html --network net007 nginx
docker run -d -p 8008:80 --name web2 -v nginx:/usr/share/nginx/html --network net007 nginx
这样可以通过 ping 命令来验证两个容器是否可以互相通信,例如进入 web 容器执行ping web2
。需要先安装 ping:
apt-get update
apt install iputils-ping
运行容器时如果不指定网络,容器间也是可以通过 ip 互联的,但是容器内的 ip 可能会变化,所以运行容器时可以指定网络然后用容器名通信。
Docker compose
Compose 项目是 Docker 官方的开源项目,用于定义和运行多个容器的工具,实现对 Docker 容器集群的快速编排,简单的理解就是处理需要多个容器相互配合来完成某项任务的场景。
Compose 中有两个重要的概念:
- 服务 (service):一个应用的容器
- 项目 (project):由一组关联的应用容器组成的一个完整业务单元,在
docker-compose.yml
文件中定义。
Compose 的默认管理对象是项目,通过子命令对项目中的一组容器进行便捷地生命周期管理。
例如一个 Web 项目,除了 Web 服务本身,可能还需要MySQL、Redis、Nginx等服务,使用 Compose 可以编写一个docker-compose.yml
文件来定义一组相关联的应用容器为一个项目,控制容器启动的顺序,实现管理多个应用容器等需求,而不用单独去维护每个容器。
安装:https://docs.docker.com/compose/install/compose-plugin/
编写 Compose 模板文件
https://docs.docker.com/compose/compose-file/
模板文件的默认名称是docker-compose.yml
,即一个YAML
格式的文件。
version: "3"
services:
docker_test:
image: docker_test:v1
container_name: dtv1
ports:
- "7001:7001"
volumes:
- docker_test_data:/tmp
networks:
- net007
depends_on:
- redis
- mysql
redis:
image: redis:6.0.8
ports:
- "6379:6379"
volumes:
- /opt/software/edis/redis.conf:/etc/redis/redis.conf
- redis_data:/data
networks:
- net007
command: redis-server /etc/redis/redis.conf
mysql:
image: mysql:5.7
environment:
MYSQL_ROOT_PASSWORD: '123456'
MYSQL_ALLOW_EMPTY_PASSWORD: 'no'
MYSQL_DATABASE: 'mytest'
MYSQL_USER: 'user01'
MYSQL_PASSWORD: '123456'
ports:
- "3306:3306"
volumes:
- mysql_data:/var/lib/mysql
- /opt/software/mysql/conf/my.cnf:/etc/my.cnf
- /opt/software/mysql/init:/docker-entrypoint-initdb.d
networks:
- net007
command: --default-authentication-plugin=mysql_native_password # 解决外部无法访问
networks:
net007:
volumes:
docker_test_data:
redis_data:
mysql_data:
在docker-compose.yml
文件目录下运行 Compose 项目:
docker-compose up
-
version
,指定 Compose 模板文件版本,和 Docker 版本有对应关系 -
services
,配置具体的服务,我们这里设计三个服务 docker_test(一个 SpringBoot 服务)、redis、mysql。注意每个服务都必须通过 image 指令指定镜像或者用build
指令指定 Dockerfile 来自动构建生成镜像,这里使用第一种。 -
networks
,配置容器连接的网络,文件最后的 networks 则是先创建网络 -
image
,指定服务的镜像 -
container_name
,指定容器名,默认使用项目名称_服务名称_序号
的格式 -
ports
,配置端口映射 -
volumes
,将容器数据挂载到宿主机。如果使用数据卷方式则需要先创建数据卷,例如文件最后的 volumes;或者直接挂载到宿主机的指定目录 -
depends_on
,设置服务间的依赖关系,被依赖的 -
command
,覆盖容器启动后默认执行的命令 -
environment
,配置容器内的环境变量
docker_test 服务对应的 Dockerfile 镜像构建文件:
FROM java:8
VOLUME /tmp # 定义匿名数据卷,SpringBoot使用的内嵌Tomcat容器默认将/tmp作为工作目录
COPY docker_test-1.0-SNAPSHOT.jar /docker_test.jar
ENTRYPOINT ["java", "-jar", "docker_test.jar"]
EXPOSE 7001
构建镜像:
docker build Dockerfile -t docker_test:v1 .
Compose 命令
https://docs.docker.com/compose/reference/
Compose 的大部分命令操作的对象既可以是项目本身,也可以指定为项目中的服务,如果没有特别指定则命令操作的对象将是项目,也就是项目中所有的服务都会受到命令影响。命令的基本格式如下:
docker-compose [-f=<arg>...] [options] [COMMAND] [ARGS...]
-
-f
,指定 Compose 文件名,默认的文件名为docker-compose.yml
-
-p
,指定项目名,默认为所在目录名称
以下是一些常用的命令,一般在模板文件目录下执行:
-
docker-compose config
,验证 Compose 文件格式是否正确 -
docker-compose up [OPTIONS] [SERVICE...]
,这个命令很重要,可以完成构建镜像,创建、启动服务容器,并关联服务相关容器等一系列操作。默认情况,docker compose up
启动的容器都在前台运行,同时如果服务容器已经存在,它将会尝试停止容器,然后重新创建。OPTIONS 常用参数:-
-d
,在后台运行服务容器。 -
--no-deps
,重新部署指定服务 -
--force-recreate
,强制重新创建容器 -
--no-recreate
,如果容器已经存在了,则不重新创建;不能和 --force-recreate 同时使用。
-
-
docker-compose ps
,列出项目中的容器 -
docker-compose restart [SERVICE...]
,重启项目中的容器,不指定服务名则重启全部 -
docker-compose stop [SERVICE...]
,停止运行的容器 -
docker-compose exec [SERVICE] sh
,进入指定容器 -
docker-compose logs [-f] [SERVICE]
,查看容器的日志