Docker学习手册
Linxu安装docker
Centos7安装docker
## 卸载旧版本的docker
$ sudo yum remove docker \
docker-client \
docker-client-latest \
docker-common \
docker-latest \
docker-latest-logrotate \
docker-logrotate \
docker-engine
## 删除docker相关文件和容器
$ rm -rf /var/lib/docker
$ rm -rf /var/lib/containerd
## yum安装gcc相关环境
$ yum -y install gcc
$ yum -y install gcc-c++
## 安装的软件包
$ sudo yum install -y yum-utils
## 设置stable镜像仓库
## docker官方仓库(血坑)
$ sudo yum-config-manager -add-repo ttps://download.docker.com/linux/centos/docker-ce.repo
## aliyun仓库(推荐使用)
$ sudo yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
## 考虑到后面都需要使用yum安装,所以可以重建一下yum索引缓存
$ sudo yum makecache fast
## 安装docker引擎
$ sudo yum install docker-ce docker-ce-cli containerd.io docker-compose-plugin
## 启动docker
$ systemctl start docker
## 查询启动状态
$ ps -ef | grep docker
## 查看docker版本
$ docker version
## 测试docker
$ docker run hello-world
Ubuntu20.04安装docker
1. 安装docker
在 Ubuntu 上安装 Docker 非常直接。我们将会启用 Docker 软件源,导入 GPG key,并且安装软件包。
首先,更新软件包索引,并且安装必要的依赖软件,来添加一个新的 HTTPS 软件源:
sudo apt update
sudo apt install apt-transport-https ca-certificates curl gnupg-agent software-properties-common
使用下面的 curl 导入源仓库的 GPG key:
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
将 Docker APT 软件源添加到你的系统:
sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
现在,Docker 软件源被启用了,你可以安装软件源中任何可用的 Docker 版本。
- 想要安装 Docker 最新版本,运行下面的命令。如果你想安装指定版本,跳过这个步骤,并且跳到下一步。
sudo apt update sudo apt install docker-ce docker-ce-cli containerd.io
- 想要安装指定版本,首先列出 Docker 软件源中所有可用的版本:
sudo apt update apt list -a docker-ce
通过在软件包名后面添加版本=来安装指定版本:
一旦安装完成,Docker 服务将会自动启动。你可以输入下面的命令,验证它:sudo apt install docker-ce=<VERSION> docker-ce-cli=<VERSION> containerd.io
输出将会类似下面这样:sudo systemctl status docker
当一个新的 Docker 发布时,你可以使用标准的sudo apt update && sudo apt upgrade流程来升级 Docker 软件包。
如果你想阻止 Docker 自动更新,锁住它的版本:sudo apt-mark hold docker-ce
2.以非Root用户执行docker
默认情况下,只有 root 或者 有 sudo 权限的用户可以执行 Docker 命令。
想要以非 root 用户执行 Docker 命令,你需要将你的用户添加到 Docker 用户组,该用户组在 Docker CE 软件包安装过程中被创建。想要这么做,输入:
sudo usermod -aG docker $USER
$USER
是一个环境变量,代表当前用户名。
登出,并且重新登录,以便用户组会员信息刷新。
3.验证安装过程
想要验证 Docker 是否已经成功被安装,你可以执行docker命令,前面不需要加`sudo, 我们将会运行一个测试容器:
docker container run hello-world
如果本地没有该镜像,这个命令将会下载测试镜像,在容器中运行它,打印出 “Hello from Docker”,并且退出。
输出看起来应该像这样:
这个容器将会在打印消息后停止运行,因为它没有任何长期运行的进程。
默认情况下,Docker 从 Docker Hub 拉取镜像。它是一个云端服务,主要用来储存 公有和私有源中的 Docker 镜像。
4.卸载docker
在卸载 Docker 之前,你最好 移除所有的容器,镜像,卷和网络。
运行下面的命令停止所有正在运行的容器,并且移除所有的 docker 对象:
docker container stop $(docker container ls -aq)
docker system prune -a --volumes
现在你可以使用apt像卸载其他软件包一样来卸载 docker:
sudo apt purge docker-ce
sudo apt autoremove
配置阿里云镜像加速
-
登录阿里云开发者平台 阿里云平台
-
点击控制台,选择容器镜像服务
-
获取加速器地址
-
粘贴脚本直接运行
注意:针对Docker客户端版本大于 1.10.0 的用户
$ sudo mkdir -p /etc/docker $ sudo tee /etc/docker/daemon.json <<-'EOF' { "registry-mirrors": ["换成自己的加速器地址"] } EOF $ sudo systemctl daemon-reload $ sudo systemctl restart docker
-
重启服务器
$ systemctl daemon-reload $ systemctl restart docker
docker常用命令
帮助启动类命令
启动docker: systemctl start docker
停止docker: systemctl stop docker
重启docker: systemctl restart docker
查看docker状态: systemctl status docker
开机启动: systemctl enable docker
关闭开机启动: systemctl disable docker
查看docker概要信息: docker info
查看docker总体帮助文档: docker --help
查看docker命令帮助文档: docker 具体命令 --help
镜像命令
docker images(列出本地主机上的镜像)
各个选项说明:
REPOSITORY:表示镜像的仓库源
TAG:镜像的标签版本号
IMAGE ID:镜像ID
CREATED:镜像创建时间
SIZE:镜像大小同一仓库源可以有多个 TAG版本,代表这个仓库源的不同个版本,我们使用 REPOSITORY:TAG 来定义不同的镜像。
如果你不指定一个镜像的版本标签,例如你只使用 ubuntu,docker 将默认使用 ubuntu:latest 镜像
OPTIONS说明:
-a : 列出本地所有的镜像
-q: 只显示镜像ID
docker search IMAGE_NAME(搜索镜像)
各个选项说明:
NAME:镜像名称
DESCRIPTION:镜像说明
STARS:点赞数量
OFFICIAL:是否是官方的
AUTOMATED:是否是自动构建的OPTIONS说明:
–limit : 只列出N个镜像,默认25个
docker search --limit 5 redis
docker pull IMAGE_NAME(拉取下载镜像)
docker pull 镜像名字[:TAG]
docker pull 镜像名字
没有TAG就是最新版等价于docker pull 镜像名称:latest
docker system df(查询镜像/容器/数据卷所占用的空间)
docker rmi 某个镜像的名字ID
删除单个: docker rmi -f 镜像ID
删除多个: docker rmi -f 镜像名1:TAG 镜像名2:TAG
删除全部: docker rmi -f $(docker images -qa)
容器命令
docker run [OPTIONS] IMAGE [COMMAND] [ARG…] (新建 + 启动容器)
OPTIONS说明(常用):有些是一个减号,有些是两个减号
–name=“容器新名字” 为容器指定一个名称;
-d: 后台运行容器并返回容器ID,也即启动守护式容器(后台运行);-i:以交互模式运行容器,通常与 -t 同时使用;
-t:为容器重新分配一个伪输入终端,通常与 -i 同时使用;
也即启动交互式容器(前台有伪终端,等待交互);-P: 随机端口映射,大写P
-p: 指定端口映射,小写p/bin/bash:放在镜像名后的是命令,这里我们希望有个交互式 Shell,因此用的是 /bin/bash。
要退出终端,直接输入 exit:
docker ps [OPTIONS] (列出当前所有正在运行的容器)
OPTIONS说明(常用):
-a : 列出当前所有正在运行的容器+历史上运行过的
-l : 显示最近创建的容器。
-n :显示最近n个创建的容器。
-q : 静默模式,只显示容器编号。
exit与ctrl+p+q(退出容器)
exit : run进去容器,exit退出,容器停止
ctrl+p+q : run进去容器,ctrl+p+q退出,容器不停止
docker [start|stop|restart|kill|rm] 容器ID ([启动|停止|重启|强制停止|删除]容器)
启动容器 : docker start 容器ID
重启容器 : docker restart容器ID
停止容器 : docker stop容器ID
强制停止容器 : docker kill容器ID
删除已停止的容器 : docker rm容器ID
一次性删除多个容器实例 : docker rm -f $(docker ps -a -q) 或者 docker ps -a -q | xargs docker rm
docker run -d 镜像名:版本 (后台守护式启动)
在大部分的场景下,我们希望 docker 的服务是在后台运行的,
我们可以过 -d 指定容器的后台运行模式。使用镜像centos:latest以后台模式启动一个容器
docker run -d centos问题:然后docker ps -a 进行查看, 会发现容器已经退出
很重要的要说明的一点: Docker容器后台运行,就必须有一个前台进程.
容器运行的命令如果不是那些一直挂起的命令(比如运行top,tail),就是会自动退出的。这个是docker的机制问题,比如你的web容器,我们以nginx为例,正常情况下,
我们配置启动服务只需要启动响应的service即可。例如service nginx start
但是,这样做,nginx为后台进程模式运行,就导致docker前台没有运行的应用,
这样的容器后台启动后,会立即自杀因为他觉得他没事可做了.
所以,最佳的解决方案是,将你要运行的程序以前台进程的形式运行,
常见就是命令行模式,表示我还有交互操作,别中断,O(∩_∩)O哈哈~
docker run -it 镜像名:版本 (前台交互式启动)
docker logs 容器ID (查询容器日志)
docker top 容器ID (查询容器内运行的进程)
docker inspect 容器ID (查询容器内部细节)
docker exec 以及 docker attach (进入正在运行的容器)
docker exec -it 容器ID bashShell
docker attach 容器ID
上述两个的区别:
attach 直接进入容器启动命令的终端,不会启动新的进程
用exit退出,会导致容器的停止。
exec 是在容器中打开新的终端,并且可以启动新的进程
用exit退出,不会导致容器的停止。
docker cp 容器ID:容器内路径 目的主机路径 (从容器内拷贝文件到主机上)
docker [export|import] (导出和导入容器)
export 导出容器的内容留作为一个tar归档文件[对应import命令]
docker export 容器ID > 文件名.tarimport 从tar包中的内容创建一个新的文件系统再导入为镜像[对应export]
cat 文件名.tar | docker import - 镜像用户/镜像名:镜像版本号
常用命令
attach Attach to a running container # 当前 shell 下 attach 连接指定运行镜像
build Build an image from a Dockerfile # 通过 Dockerfile 定制镜像
commit Create a new image from a container changes # 提交当前容器为新的镜像
cp Copy files/folders from the containers filesystem to the host path #从容器中拷贝指定文件或者目录到宿主机中
create Create a new container # 创建一个新的容器,同 run,但不启动容器
diff Inspect changes on a container’s filesystem # 查看 docker 容器变化
events Get real time events from the server # 从 docker 服务获取容器实时事件
exec Run a command in an existing container # 在已存在的容器上运行命令
export Stream the contents of a container as a tar archive # 导出容器的内容流作为一个 tar 归档文件[对应 import ]
history Show the history of an image # 展示一个镜像形成历史
images List images # 列出系统当前镜像
import Create a new filesystem image from the contents of a tarball # 从tar包中的内容创建一个新的文件系统映像[对应export]
info Display system-wide information # 显示系统相关信息
inspect Return low-level information on a container # 查看容器详细信息
kill Kill a running container # kill 指定 docker 容器
load Load an image from a tar archive # 从一个 tar 包中加载一个镜像[对应 save]
login Register or Login to the docker registry server # 注册或者登陆一个 docker 源服务器
logout Log out from a Docker registry server # 从当前 Docker registry 退出
logs Fetch the logs of a container # 输出当前容器日志信息
port Lookup the public-facing port which is NAT-ed to PRIVATE_PORT # 查看映射端口对应的容器内部源端口
pause Pause all processes within a container # 暂停容器
ps List containers # 列出容器列表
pull Pull an image or a repository from the docker registry server # 从docker镜像源服务器拉取指定镜像或者库镜像
push Push an image or a repository to the docker registry server # 推送指定镜像或者库镜像至docker源服务器
restart Restart a running container # 重启运行的容器
rm Remove one or more containers # 移除一个或者多个容器
rmi Remove one or more images # 移除一个或多个镜像[无容器使用该镜像才可删除,否则需删除相关容器才可继续或 -f 强制删除]
run Run a command in a new container # 创建一个新的容器并运行一个命令
save Save an image to a tar archive # 保存一个镜像为一个 tar 包[对应 load]
search Search for an image on the Docker Hub # 在 docker hub 中搜索镜像
start Start a stopped containers # 启动容器
stop Stop a running containers # 停止容器
tag Tag an image into a repository # 给源中镜像打标签
top Lookup the running processes of a container # 查看容器中运行的进程信息
unpause Unpause a paused container # 取消暂停容器
version Show the docker version information # 查看 docker 版本号
wait Block until a container stops, then print its exit code # 截取容器停止时的退出状态值
docker镜像介绍
镜像是什么
镜像是一种轻量级、可执行的独立软件包,它包含运行某个软件所需的所有内容,我们把应用程序和配置依赖打包好形成一个可交付的运行环境(包括代码、运行时需要的库、环境变量和配置文件等),这个打包好的运行环境就是image镜像文件。
只有通过这个镜像文件才能生成Docker容器实例(类似Java中new出来一个对象)。
分层的镜像
以我们pull镜像为例,在下载过程中我们可以看到docker的镜像好像是在一层一层的在下载
为什么会出现上面的那种情况呢?
UnionFS(联合文件系统):Union文件系统(UnionFS)是一种分层、轻量级并且高性能的文件系统,它支持对文件系统的修改作为一次提交来一层层的叠加,同时可以将不同目录挂载到同一个虚拟文件系统下(unite several directories into a single virtual filesystem)。Union 文件系统是 Docker 镜像的基础。镜像可以通过分层来进行继承,基于基础镜像(没有父镜像),可以制作各种具体的应用镜像。
特性:一次同时加载多个文件系统,但从外面看起来,只能看到一个文件系统,联合加载会把各层文件系统叠加起来,这样最终的文件系统会包含所有底层的文件和目录
docker镜像加载原理
docker的镜像实际上由一层一层的文件系统组成,这种层级的文件系统UnionFS。
bootfs(boot file system)主要包含bootloader和kernel, bootloader主要是引导加载kernel, Linux刚启动时会加载bootfs文件系统,在Docker镜像的最底层是引导文件系统bootfs。这一层与我们典型的Linux/Unix系统是一样的,包含boot加载器和内核。当boot加载完成之后整个内核就都在内存中了,此时内存的使用权已由bootfs转交给内核,此时系统也会卸载bootfs。
rootfs (root file system) ,在bootfs之上。包含的就是典型 Linux 系统中的 /dev, /proc, /bin, /etc 等标准目录和文件。rootfs就是各种不同的操作系统发行版,比如Ubuntu,Centos等等。
平时我们安装进虚拟机的CentOS都是好几个G,为什么docker这里才230M??
对于一个精简的OS,rootfs可以很小,只需要包括最基本的命令、工具和程序库就可以了,因为底层直接用Host的kernel,自己只需要提供 rootfs 就行了。由此可见对于不同的linux发行版, bootfs基本是一致的, rootfs会有差别, 因此不同的发行版可以公用bootfs。
为什么docker镜像要采用这种分层结构呢
镜像分层最大的一个好处就是共享资源,方便复制迁移,就是为了复用。
比如说有多个镜像都从相同的 base 镜像构建而来,那么 Docker Host 只需在磁盘上保存一份 base 镜像;
同时内存中也只需加载一份 base 镜像,就可以为所有容器服务了。而且镜像的每一层都可以被共享。
镜像层和容器层
Docker镜像层都是只读的,容器层是可写的
当容器启动时,一个新的可写层被加载到镜像的顶部。
这一层通常被称作“容器层”,“容器层”之下的都叫“镜像层”。
当容器启动时,一个新的可写层被加载到镜像的顶部。这一层通常被称作“容器层”,“容器层”之下的都叫“镜像层”。
所有对容器的改动 - 无论添加、删除、还是修改文件都只会发生在容器层中。只有容器层是可写的,容器层下面的所有镜像层都是只读的。
docker镜像commit操作案例
docker commit提交容器副本使之成为一个新的镜像
docker commit -m="提交的描述信息" -a="作者" 容器ID 要创建的目标镜像名:[标签名]
- 从镜像仓库中下载centos镜像
docker pull centos:centos7.6.1810
- 启动镜像,进入到镜像中
docker run -it 镜像ID /bin/bash
- 使用vim命令
vim a.txt
,这个时候可以发现是在提示command not found,代表vim命令不存在 (原始的默认的centos镜像是不带着vim命令的) - 外网连通的情况下,安装vim
- 先更新yum
yum update
- 安装vim
yum install vim
- 先更新yum
- 安装完成后,commit我们自己的新镜像
docker commit -m="install vim" -a="JunPzx" b28ff2490501 my_centos7.6:1.0
- 启动我们的新镜像并和原来的对比
总结
Docker中的镜像分层,支持通过扩展现有镜像,创建新的镜像。类似Java继承于一个Base基础类,自己再按需扩展。
新镜像是从 base 镜像一层一层叠加生成的。每安装一个软件,就在现有镜像的基础上增加一层
docker镜像与容器导入导出
镜像导入导出
# 导出镜像语法
docker save -o file.tar images:tag
# 导出镜像案例
docker save -o mysql57.tar mysql:5.7
# 导入镜像语法
docker load < file.tar
# 导入镜像案例
docker load < mysql57.tar
除上面的镜像导出语法外,也可以直接使用docker save <image_id> > file.tar
进行导出,但是这样导出的镜像在导入后,有部分信息为<none>,如镜像名称和标签那些,需要使用docker tag <image_id> image_name:tag
进行修改后使用。
容器导入导出
# 导出容器语法
docker export <container_id> > file.tar
# 导出容器案例
docker export f299f501774c > test.tar
# 导入容器语法
docker import - <container_name> < file.tar
# 导入容器案例
docker import - test_server < test.tar
docker本地镜像发布
发布到阿里云
1.在阿里云中创建命名空间和仓库
2.按照基本信息中的命令进行授权和上传
$ docker login --username=阿里云账户名 registry.cn-hangzhou.aliyuncs.com
$ docker tag [ImageId] registry.cn-hangzhou.aliyuncs.com/pzx/mycentos:[镜像版本号]
$ docker push registry.cn-hangzhou.aliyuncs.com/pzx/mycentos:[镜像版本号]
## 酌情将上述命令更换成自己的,最好直接在阿里云的镜像管理界面直接copy
3.将阿里云上刚才上传的镜像拉取到本地进行对比
$ docker pull registry.cn-hangzhou.aliyuncs.com/pzx/mycentos:[镜像版本号]
发布到私有库中
官方Docker Hub地址:https://hub.docker.com/,中国大陆访问太慢了且准备被阿里云取代的趋势,不太主流。
Dockerhub、阿里云这样的公共镜像仓库可能不太方便,涉及机密的公司不可能提供镜像给公网,所以需要创建一个本地私人仓库供给团队使用,基于公司内部项目构建镜像。
Docker Registry是官方提供的工具,可以用于构建私有镜像仓库
1.下载镜像docker registry
$ dcoker pull registry
2.运行私有库Registry,相当于本地有个私有Docker hub
$ docker run -d -p 5000:5000 -v /junpzx/myregistry/:/tmp/registry --privileged=true registry
默认情况,仓库被创建在容器的/var/lib/registry目录下,建议自行用容器卷映射,方便于宿主机联调
3.创建一个新的centos7.6镜像,并在上面安装ifconfig命令
$ docker run -it f1cb7c7d58b7 /bin/bash
## 在容器输入
$ yum update -y
$ yum install -y net-tools
4.安装完成后,commit新镜像,并进行验证
## docker commit -m="提交的描述信息" -a="作者" 容器ID 要创建的目标镜像名:[标签名]
$ docker commit -m="add net-tools" -a="JunPzx" b3a2801a5b4b my_centos_nettools:1.0
$ docker run -it 9b9663359cc7 /bin/bash
5.curl验证私服库上有什么镜像
$ curl -XGET http://192.168.0.176:5000/v2/_catalog
可以看到私服上现在没有任何镜像
6.将新镜像my_centos_nettools:1.0修复符合私服规范的Tag
## docker tag 镜像:Tag Host:Port/Repository:Tag
$ docker tag my_centos_nettools:1.0 192.168.0.176:5000/my_centos_nettools:1.0
7.修改docker配置文件,使其支持http
$ cat /etc/docker/daemon.json
{
"registry-mirrors": ["https://glf6srex.mirror.aliyuncs.com"]
}
$ vim /etc/docker/daemon.json
{
"registry-mirrors": ["https://glf6srex.mirror.aliyuncs.com"],
"insecure-registries": ["192.168.0.176:5000"]
}
docker默认不允许http方式推送镜像,通过配置选项来取消这个限制。====> 修改完后如果不生效,建议重启docker
8.推送到私服库中
$ docker push 192.168.0.176:5000/my_centos_nettools:1.0
## 验证docker私服中是否有该镜像
$ curl -XGET http://192.168.0.176:5000/v2/_catalog
9.拉取到本地并运行
$ docker pull 192.168.0.176:5000/my_centos_nettools:1.0
docker容器数据卷
卷就是目录或文件,存在于一个或多个容器中,由docker挂载到容器,但不属于联合文件系统,因此能够绕过Union File System提供一些用于持续存储或共享数据的特性:
卷的设计目的就是数据的持久化,完全独立于容器的生存周期,因此Docker不会在容器删除时删除其挂载的数据卷
$ docker run -it --privileged=true -v /宿主机绝对路径目录:/容器内目录 镜像名
作用
将运用与运行的环境打包镜像,run后形成容器实例运行 ,但是我们对数据的要求希望是持久化的
Docker容器产生的数据,如果不备份,那么当容器实例删除后,容器内的数据自然也就没有了。
为了能保存数据在docker中我们使用卷。
特点:
1:数据卷可在容器之间共享或重用数据
2:卷中的更改可以直接实时生效,爽
3:数据卷中的更改不会包含在镜像的更新中
4:数据卷的生命周期一直持续到没有容器使用它为止
卷的继承和共享
$ docker run -it --privileged=true --volumes-from 父类 --name centos1 centos
🚨坑
在绑定容器卷时记得加上 --privileged=true
Docker挂载主机目录访问如果出现cannot open directory .: Permission denied
解决办法:在挂载目录后多加一个–privileged=true参数即可
如果是CentOS7安全模块会比之前系统版本加强,不安全的会先禁止,所以目录挂载的情况被默认为不安全的行为,
在SELinux里面挂载目录被禁止掉了额,如果要开启,我们一般使用–privileged=true命令,扩大容器的权限解决挂载目录没有权限的问题,也即
使用该参数,container内的root拥有真正的root权限,否则,container内的root只是外部的一个普通用户权限。
Dockerfile解析
Dockerfile是用来构建Docker镜像的文本文件,是由一条条构建镜像所需的指令和参数构成的脚本。
Dockerfile构建过程解析
基本知识
- 每条保留字指令都必须为大写字母且后面要跟随至少一个参数
- 每天指令从上到下,顺序执行
- #表示注释
- 每条指令都会创建一个新的镜像层并对镜像进行提交
执行流程
- docker从基础镜像运行一个容器
- 执行一条指令并对容器作出修改
- 执行类似docker commit的操作提交一个新的镜像层
- docker再基于刚提交的镜像运行一个新容器
- 执行dockerfile中的下一条指令直到所有指令都执行完成
小总结
从应用软件的角度来看,Dockerfile、Docker镜像与Docker容器分别代表软件的三个不同阶段,
-
Dockerfile是软件的原材料
-
Docker镜像是软件的交付品
-
Docker容器则可以认为是软件镜像的运行态,也即依照镜像运行的容器实例
Dockerfile面向开发,Docker镜像成为交付标准,Docker容器则涉及部署与运维,三者缺一不可,合力充当Docker体系的基石。
- Dockerfile,需要定义一个Dockerfile,Dockerfile定义了进程需要的一切东西。Dockerfile涉及的内容包括执行代码或者是文件、环境变量、依赖包、运行时环境、动态链接库、操作系统的发行版、服务进程和内核进程(当应用进程需要和系统服务和内核进程打交道,这时需要考虑如何设计namespace的权限控制)等等;
- Docker镜像,在用Dockerfile定义一个文件之后,docker build时会产生一个Docker镜像,当运行 Docker镜像时会真正开始提供服务;
- Docker容器,容器是直接提供服务的。
Dockerfile常用保留字指令
- FROM
- 基础镜像,当前新镜像是基于哪个镜像的,指定一个已经存在的镜像作为模板,第一条必须是from
- MAINTAINER
- 镜像维护者的姓名和邮箱地址
- RUN
- 容器构建时需要运行的命令
- 两种格式
- shell格式
- exec格式
- RUN是在 docker build时运行
- EXPOSE
- 当前容器对外暴露出的端口
- WORKDIR
- 指定在创建容器后,终端默认登陆的进来工作目录,一个落脚点
- USER
- 指定该镜像以什么样的用户去执行,如果都不指定,默认是root
- ENV
- 用来在构建镜像过程中设置环境变量
- ENV MY_PATH /usr/mytest这个环境变量可以在后续的任何RUN指令中使用,这就如同在命令前面指定了环境变量前缀一样;也可以在其它指令中直接使用这些环境变量,比如:WORKDIR $MY_PATH
- ARG
- 定义创建镜像过程中使用的变量,当镜像编译成功后,ARG 指定的变量将不再存在(ENV指定的变量将在镜像中保留)
- ARG <name>[=<default value>]
- ARG 和 ENV 的区别
- ARG 定义的变量只会存在于镜像构建过程,启动容器后并不保留这些变量
- ENV 定义的变量在启动容器后仍然保留
- 注意:
- 不要通过 ARG 保存密码之类的信息,因为 docker history 还是可以看到所有值的
- 如果在 FROM 指令之前指定,那么只能用于 FROM 指令中
- ADD
- 将宿主机目录下的文件拷贝进镜像且会自动处理URL和解压tar压缩包
- COPY
- 类似ADD,拷贝文件和目录到镜像中。将从构建上下文目录中 <源路径> 的文件/目录复制到新的一层的镜像内的 <目标路径> 位置
- COPY src dest
- COPY [“src”, “dest”]
- <src源路径>:源文件或者源目录
- <dest目标路径>:容器内的指定路径,该路径不用事先建好,路径不存在的话,会自动创建。
- 类似ADD,拷贝文件和目录到镜像中。将从构建上下文目录中 <源路径> 的文件/目录复制到新的一层的镜像内的 <目标路径> 位置
- VOLUME
- 容器数据卷,用于数据保存和持久化工作
- CMD
- 指定容器启动后的要干的事情
- CMD指令的格式和RUN相似,也是两种格式
- shell格式:
CMD <命令>
- exec格式:
CMD ["可执行文件","参数1","参数2"...]
- 参数列表格式:
CMD["参数1","参数2"...]
,在指定了ENTRYPOINT指令后,用CMD指定具体的参数
- shell格式:
- 注意
- Dockerfile 中可以有多个 CMD 指令,但只有最后一个生效,CMD 会被 docker run 之后的参数替换
- 它和前面RUN命令的区别
- CMD是在docker run 时运行。
- RUN是在 docker build时运行。
- ENTRYPOINT
- 也是用来指定一个容器启动时要运行的命令
- 类似于 CMD 指令,但是ENTRYPOINT不会被docker run后面的命令覆盖,而且这些命令行参数会被当作参数送给 ENTRYPOINT 指令指定的程序
- 优点
- 在执行docker run的时候可以指定 ENTRYPOINT 运行所需的参数。
- 注意
- 如果 Dockerfile 中如果存在多个 ENTRYPOINT 指令,仅最后一个生效。
小案例
自定义镜像mycentos,要求centos7镜像具备vim + ifconfig + jdk8
JDK的下载地址: https://mirrors.yangxingzhen.com/jdk/
Dockerfile文件(注意文件名为 Dokcerfile 无文件类型,D为大写,file为小写),注意将jdk和Dockerfile放在同一级目录中,以下为Dockerfile文件内容
# 基础镜像
FROM centos:centos7.6.1810
# 维护人信息
MAINTAINER junpzx<junpzx@163.com>
# 定义环境变量
ENV MYPATH /usr/local
# 设置进入容器时的默认目录
WORKDIR $MYPATH
# 安装vim编辑器
RUN yum -y install vim
# 安装ifconfig命令查看网络IP
RUN yum -y install net-tools
# 安装java8及lib库
RUN yum -y install glibc.i686
RUN mkdir /usr/local/java
# ADD 是相对路径,把jdk-8u191-linux-x64.tar.gz添加到容器中,安装包必须要和Dockerfile文件在同一位置
# 添加到镜像中时,会自动解压的
ADD jdk-8u191-linux-x64.tar.gz /usr/local/java/
# 配置java环境变量
ENV JAVA_HOME /usr/local/java/jdk1.8.0_191
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
EXPOSE 80
CMD echo $MYPATH
CMD echo "success--------------ok"
CMD /bin/bash
在Dockerfile和jdk存放的文件夹下执行命令:
# TAG后面有个空格,有个点
docker build -t mycentos:1.0.0 .
# 等待镜像生成完毕后,运行镜像
docker run -it mycentos:1.0.0
# 进入镜像中,进行验证
ifconfig
vim a.txt
java -version
虚悬镜像现象
仓库名、标签都是<none>的镜像,俗称dangling image
# 查看虚悬镜像
docker image ls -f dangling=true
# 删除虚悬镜像
docker image prune
docker网络
在docker启动后,在控制台中输入ifconfig,会出现一个docker0的网络配置,这就是docker默认的虚拟网桥;
作用:
- 容器间的互联和通信以及端口映射
- 容器IP变动时候可以通过服务名直接网络通信而不受到影响
常用基本命令
# 查看网络
docker network ls
# 查看网络源数据
docker network inspect xx网络名称
# 删除网络
docker network rm xx网络名称
# 创建新网络
docker network create xx网络名称
# docker network create --driver 模式 --subnet 网段 --gateway 网关 xx网络名称
docker network create --driver bridge --subnet 192.168.0.0/16 --gateway 192.168.0.1 mynetwork
# 查询容器的网络信息
docker inspect xxxx容器名
docker inpsect xxx容器名 | tail -n 20
网络模式
- bridge模式:使用–network bridge指定,默认使用docker0
- host模式:使用–network host指定
- none模式:使用–network none指定
- container模式:使用–network container:NAME或者容器ID指定
bridge模式
Docker 服务默认会创建一个 docker0 网桥(其上有一个 docker0 内部接口),该桥接网络的名称为docker0,它在内核层连通了其他的物理或虚拟网卡,这就将所有容器和本地主机都放到同一个物理网络。Docker 默认指定了 docker0 接口 的 IP 地址和子网掩码,让主机和容器之间可以通过网桥相互通信。
- Docker使用Linux桥接,在宿主机虚拟一个Docker容器网桥(docker0),Docker启动一个容器时会根据Docker网桥的网段分配给容器一个IP地址,称为Container-IP,同时Docker网桥是每个容器的默认网关。因为在同一宿主机内的容器都接入同一个网桥,这样容器之间就能够通过容器的Container-IP直接通信。
- docker run 的时候,没有指定network的话默认使用的网桥模式就是bridge,使用的就是docker0。在宿主机ifconfig,就可以看到docker0和自己create的network(后面讲)eth0,eth1,eth2……代表网卡一,网卡二,网卡三……,lo代表127.0.0.1,即localhost,inet addr用来表示网卡的IP地址
- 网桥docker0创建一对对等虚拟设备接口一个叫veth,另一个叫eth0,成对匹配。
- 整个宿主机的网桥模式都是docker0,类似一个交换机有一堆接口,每个接口叫veth,在本地主机和容器内分别创建一个虚拟接口,并让他们彼此联通(这样一对接口叫veth pair);
- 每个容器实例内部也有一块网卡,每个接口叫eth0;
- docker0上面的每个veth匹配某个容器实例内部的eth0,两两配对,一一匹配。通过上述,将宿主机上的所有容器都连接到这个内部网络上,两个容器在同一个网络下,会从这个网关下各自拿到分配的ip,此时两个容器的网络是互通的。
bridge模式中,当启动容器时,docker会为容器分配一个IP地址,但是该IP地址并不是一直属于该容器的,如果该容器停止后有其他容器启动,当停止的容器的IP再次启动时,此时的IP和以往不同,所以不同容器进行访问时,尽量使用容器名来进行访问,但是如果使用的是默认的网络,也就是在创建容器时没指定自定义的网络,那么通过容器名是互相访问不到的,所以尽量自定义网络,并互相通过容器名进行访问
也可以不使用自定义网络,在创建容器时使用–link 参数,但是该参数已过时,假如
docker run -it centos:centos7.6.1810 --name mycentos1 /bin/bash
docker run -it centos:centos7.6.1810 --name mycentos2 --link mycentos1 /bin/bash–link这是一个单向的,也就是只有写了–link的才能ping,就像mycentos1没写–link,mycentos2能ping mycentos1,但是mycentos1ping不通mycentos2
⚠️ Warning
The
--link
flag is a legacy feature of Docker. It may eventually be removed. Unless you absolutely need to continue using it, we recommend that you use user-defined networks to facilitate communication between two containers instead of using--link
. One feature that user-defined networks do not support that you can do with--link
is sharing environment variables between containers. However, you can use other mechanisms such as volumes to share environment variables between containers in a more controlled way.该
--link
标志是 Docker 的遗留功能。它最终可能会被删除。除非您绝对需要继续使用它,否则我们建议您使用用户定义的网络来促进两个容器之间的通信,而不是使用--link
. 用户定义的网络不支持您可以使用的一项功能--link
是在容器之间共享环境变量。但是,您可以使用其他机制(例如卷)以更可控的方式在容器之间共享环境变量。See Differences between user-defined bridges and the default bridge for some alternatives to using
--link
.总结: --link已经过时,尽量不要使用 https://docs.docker.com/network/links/
host模式
直接使用宿主机的 IP 地址与外界进行通信,不再需要额外进行NAT 转换。
容器将不会获得一个独立的Network Namespace, 而是和宿主机共用一个Network Namespace。容器将不会虚拟出自己的网卡而是使用宿主机的IP和端口。
docker run -d -p 8083:8080 --network host --name tomcat83 billygoo/tomcat8-jdk8
docker执行以上或相似命令时遇到警告WARNING: Published ports are discarded when using host network mode,这是因为 docker启动时指定–network=host或-net=host,如果还指定了-p映射端口,那这个时候就会有此警告,并且通过-p设置的参数将不会起到任何作用,端口号会以主机端口号为主,重复时则递增。
none模式
在none模式下,并不为Docker容器进行任何网络配置。 也就是说,这个Docker容器没有网卡、IP、路由等信息,只有一个lo需要我们自己为Docker容器添加网卡、配置IP等。禁用网络功能,只有lo标识(就是127.0.0.1表示本地回环)
container模式
新建的容器和已经存在的一个容器共享一个网络ip配置而不是和宿主机共享。新创建的容器不会创建自己的网卡,配置自己的IP,而是和一个指定的容器共享IP、端口范围等。同样,两个容器除了网络方面,其他的如文件系统、进程列表等还是隔离的。
docker平台架构图解
从其架构和运行流程来看,Docker 是一个 C/S 模式的架构,后端是一个松耦合架构,众多模块各司其职。 Docker 运行的基本流程为:
- 用户是使用 Docker Client 与 Docker Daemon 建立通信,并发送请求给后者。
- Docker Daemon 作为 Docker 架构中的主体部分,首先提供 Docker Server 的功能使其可以接受 Docker Client 的请求。
- Docker Engine 执行 Docker 内部的一系列工作,每一项工作都是以一个 Job 的形式的存在。
- Job 的运行过程中,当需要容器镜像时,则从 Docker Registry 中下载镜像,并通过镜像管理驱动 Graph driver将下载镜像以Graph的形式存储。
- 当需要为 Docker 创建网络环境时,通过网络管理驱动 Network driver 创建并配置 Docker 容器网络环境。
- 当需要限制 Docker 容器运行资源或执行用户指令等操作时,则通过 Execdriver 来完成。
- Libcontainer是一项独立的容器管理包,Network driver以及Exec driver都是通过Libcontainer来实现具体对容器进行的操作。
Docker-compose容器编排
Compose 是 Docker 公司推出的一个工具软件,可以管理多个 Docker 容器组成一个应用。你需要定义一个 YAML 格式的配置文件docker-compose.yml,写好多个容器之间的调用关系。然后,只要一个命令,就能同时启动/关闭这些容器
docker建议我们每一个容器中只运行一个服务,因为docker容器本身占用资源极少,所以最好是将每个服务单独的分割开来但是这样我们又面临了一个问题?
如果我需要同时部署好多个服务,难道要每个服务单独写Dockerfile然后在构建镜像,构建容器,这样累都累死了,所以docker官方给我们提供了docker-compose多服务部署的工具
例如要实现一个Web微服务项目,除了Web服务容器本身,往往还需要再加上后端的数据库mysql服务容器,redis服务器,注册中心eureka,甚至还包括负载均衡容器等等。。。。。。
Compose允许用户通过一个单独的docker-compose.yml模板文件(YAML 格式)来定义一组相关联的应用容器为一个项目(project)。
可以很容易地用一个配置文件定义一个多容器的应用,然后使用一条指令安装这个应用的所有依赖,完成构建。Docker-Compose 解决了容器与容器之间如何管理编排的问题。
安装
# 官网地址 https://docs.docker.com/compose/compose-file/compose-file-v3/
# 下载地址 https://docs.docker.com/compose/install/
# 安装
curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
# 赋予执行权限
chmod +x /usr/local/bin/docker-compose
# 验证是否安装成功
docker-compose --version
# 卸载(适用于curl安装的方式)
rm /usr/local/bin/docker-compose
compose核心概念
一文件,两要素
一文件 : docker-compose.yml
两要素 :
- 服务(service) : 一个个应用容器实例,比如订单微服务、库存微服务、mysql容器、nginx容器或者redis容器
- 工程(project) : 由一组关联的应用容器组成的一个完整业务单元,在 docker-compose.yml 文件中定义。
使用步骤
- 编写Dockerfile定义各个微服务应用并构建出对应的镜像文件
- 使用 docker-compose.yml 定义一个完整业务单元,安排好整体应用中的各个容器服务。
- 最后,执行docker-compose up命令 来启动并运行整个应用程序,完成一键部署上线
常用命令
# 查看帮助
docker-compose -h
# 启动所有docker-compose服务
docker-compose up
# 启动所有docker-compose服务并后台运行
docker-compose up -d
# 停止并删除容器、网络、卷、镜像。
docker-compose down
# 进入容器实例内部 docker-compose exec docker-compose.yml文件中写的服务id /bin/bash
docker-compose exec yml里面的服务id
# 展示当前docker-compose编排过的运行的所有容器
docker-compose ps
# 展示当前docker-compose编排过的容器进程
docker-compose top
# 查看容器输出日志
docker-compose logs yml里面的服务id
# 检查配置
docker-compose config
# 检查配置,有问题才有输出
docker-compose config -q
# 重启服务
docker-compose restart
# 启动服务
docker-compose start
# 停止服务
docker-compose stop