一、相关概念
1、三要素
镜像、容器、仓库
容器是基于镜像文件生成的,相当于java中的类和对象的关系
仓库是存放镜像的地方
世界最大的公开仓库:https://hub.docker.com/
docker官网:http://www.docker.com
2、工作原理
二、centos7安装docker
1、安装
(1)卸载旧版本
较旧的 Docker 版本称为 docker 或 docker-engine 。如果已安装这些程序,请卸载它们以及相关的依赖项。
sudo yum remove docker \
docker-client \
docker-client-latest \
docker-common \
docker-latest \
docker-latest-logrotate \
docker-logrotate \
docker-engine
(2)设置docker仓库
在新主机上首次安装 Docker Engine-Community 之前,需要设置 Docker 仓库。之后,您可以从仓库安装和更新 Docker。
前置环境安装
yum -y install gcc
yum -y install gcc-c++
安装所需的软件包
安装所需的软件包。yum-utils 提供了 yum-config-manager ,并且 device mapper 存储驱动程序需要 device-mapper-persistent-data 和 lvm2。
sudo yum install -y yum-utils device-mapper-persistent-data lvm2
设置阿里云仓库
sudo yum-config-manager \
--add-repo \
http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
(3)安装docker
最新版
安装最新版本的 Docker Engine-Community 和 containerd,之后会提示几个是否接受,无脑y就行
sudo yum install docker-ce docker-ce-cli containerd.io
Docker 安装完默认未启动。并且已经创建好 docker 用户组,但该用户组下没有用户。
启动 docker
sudo systemctl start docker
如果启动报错
failed to start daemon: Error initializing network controller: Error creating default "bridge" network: Failed to program NAT
则关闭防火墙即可
sudo systemctl stop firewalld
开机自启
sudo systemctl enable docker
通过启动命令启动后可通过以下命令判断是否安装成功
docker version
有client和service两部分表示docker安装启动都成功了
(4)配置镜像加速
国内从 DockerHub 拉取镜像有时会遇到困难,此时可以配置镜像加速器。Docker 官方和国内很多云服务商都提供了国内加速器服务,例如:
- 科大镜像:https://docker.mirrors.ustc.edu.cn/
- 网易:https://hub-mirror.c.163.com/
- 阿里云:https://<你的ID>.mirror.aliyuncs.com
- 七牛云加速器:https://reg-mirror.qiniu.com
当配置某一个加速器地址之后,若发现拉取不到镜像,请切换到另一个加速器地址。国内各大云服务商均提供了 Docker 镜像加速服务,建议根据运行 Docker 的云平台选择对应的镜像加速服务。
阿里云镜像获取地址:https://cr.console.aliyun.com/cn-hangzhou/instances/mirrors,登陆后,左侧菜单选中镜像加速器就可以看到你的专属地址了:
执行以下命令即可
sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{
"registry-mirrors": ["阿里云的加速器地址"]
}
EOF
sudo systemctl daemon-reload
sudo systemctl restart docker
查看镜像加速是否生效
docker info
有以下语句即生效
Registry Mirrors:
https://对应阿里云加速地址
(5)完整安装脚本
#!/bin/bash
sudo yum remove docker \
docker-client \
docker-client-latest \
docker-common \
docker-latest \
docker-latest-logrotate \
docker-logrotate \
docker-engine
yum -y install gcc
yum -y install gcc-c++
sudo yum install -y yum-utils device-mapper-persistent-data lvm2
sudo yum-config-manager \
--add-repo \
http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
sudo yum install -y docker-ce docker-ce-cli containerd.io
sudo systemctl start docker
sudo systemctl enable docker
2、启动命令
启动
sudo systemctl start docker
开机自启
sudo systemctl enable docker
停止 docker
systemctl stop docker
重启 docker
systemctl restart docker
查看docker状态
systemctl status docker
3、卸载
关闭 docker
systemctl stop docker
删除安装包
yum remove docker-ce docker-ce-cli containerd.io
删除镜像、容器、配置文件等内容:
rm -rf /var/lib/docker
rm -rf /var/lib/containerd
二、常用命令
1、镜像
(1)查看所有镜像
docker images
可用参数:
- -a :列出本地所有的镜像(含历史映像层)
- -q :只显示镜像ID。
REPOSITORY TAG IMAGE ID CREATED SIZE
ubuntu 14.04 90d5884b1ee0 5 days ago 188 MB
php 5.6 f40e9e0f10c8 9 days ago 444.8 MB
nginx latest 6f8d099c3adc 12 days ago 182.7 MB
mysql 5.6 f2e8d6c772c0 3 weeks ago 324.6 MB
httpd latest 02ef73cf1bc0 3 weeks ago 194.4 MB
ubuntu 15.10 4e3b13c8a266 4 weeks ago 136.3 MB
hello-world latest 690ed74de00f 6 months ago 960 B
training/webapp latest 6fae60ef3446 11 months ago 348.8
各个参数说明:
- REPOSITORY:表示镜像的仓库源
- TAG:镜像的标签
- IMAGE ID:镜像ID
- CREATED:镜像创建时间
- SIZE:镜像大小
同一仓库源可以有多个 TAG,代表这个仓库源的不同个版本,如 ubuntu 仓库源里,有 15.10、14.04 等多个不同的版本,我们使用 REPOSITORY:TAG 来定义不同的镜像。
(2)查找镜像
我们可以从 Docker Hub 网站来搜索镜像,Docker Hub 网址为: https://hub.docker.com/
我们也可以使用 docker search 命令来搜索镜像。比如我们需要一个 httpd 的镜像来作为我们的 web 服务。我们可以通过 docker search 命令搜索 httpd 来寻找适合我们的镜像。
docker search httpd
可用选项:
- –limitN : 只列出N个镜像,默认25个,
docker search --limit 5 redis
输出列表解析:
NAME: 镜像仓库源的名称
DESCRIPTION: 镜像的描述
OFFICIAL: 是否 docker 官方发布
stars: 类似 Github 里面的 star,表示点赞、喜欢的意思。
AUTOMATED: 自动构建。
(3)拉取镜像
docker pull 镜像名字[:TAG]
没有TAG就是最新版,等价于 docker pull 镜像名字:latest
(4)删除镜像
删除指定
docker rmi hello-world
删除多个
docker rmi -f 镜像名1:TAG 镜像名2:TAG
删除全部
docker rmi -f $(docker images -qa)
(5)导出镜像
docker image save nginx > nginx.tar # 导出niginx镜像
(6)查看占用空间
查看镜像/容器/数据卷所占的空间
docker system df
(7)根据名称查询镜像ID
docker images -q --filter reference=nginx
-q:只显示id
2、容器
(1)查看所有容器
docker ps -a
-a:查询全部,默认查询已启动
-f:根据提供的条件过滤输出
-q:只显示id
示例:查询 容器名为 nginx 的容器
docker ps -f name=nginx
列出指定容器的详细信息
docker inspect web4 # 列出指定容器的详细信息
(2)生成容器
docker run [OPTIONS] IMAGE [COMMAND] [ARG...]
前台交互式启动
docker run -it ubuntu:15.10 /bin/bash
-it 容器 /bin/bash
:创建容器并进入容器终端
后台守护式启动,一般用-d后台启动的程序,再用exec进入对应容器实例
docker run -d redis:6.0.8
参数说明:
- -i: 交互式操作。
- -t: 终端。为容器重新分配一个伪输入终端,通常与 -i 同时使用
- ubuntu:15.10: 这是指用 ubuntu 15.10 版本镜像为基础来启动容器。
- /bin/bash:放在镜像名后的是命令,这里我们希望有个交互式 Shell,因此用的是 /bin/bash。
#docker run常用参数
-d # 后台运行容器,并返回容器ID;
-i # 以交互模式运行容器,通常与 -t 同时使用;
-t # 为容器重新分配一个伪输入终端,通常与 -i 同时使用;
-P # 随机端口映射,容器内部端口随机映射到主机的高端口
-p # 指定端口映射,格式为:主机(宿主)端口:容器端口
--name="nginx-lb" # 为容器指定一个名称;
--dns 8.8.8.8 # 指定容器使用的DNS服务器,默认和宿主一致;
--dns-search example.com: 指定容器DNS搜索域名,默认和宿主一致;
-h "mars": 指定容器的hostname;
-e username="ritchie": 设置环境变量;
--env JENKINS_OPTS="–prefix=/jenkins":设置环境变量;
--env-file=[]: 从指定文件读入环境变量;
--cpuset="0-2" or --cpuset="0,1,2": 绑定容器到指定CPU运行;
-m :设置容器使用内存最大值;
--net="bridge": 指定容器的网络连接类型,支持 bridge/host/none/container: 四种类型;
--link=[]: 添加链接到另一个容器;
--expose=[]: 开放一个端口或一组端口;
--volume , -v: 绑定一个卷
-a stdin: 指定标准输入输出内容类型,可选 STDIN/STDOUT/STDERR 三项;
–-restart=always 机器重启时自动启动容器
-p 8800:80 # 宿主机的8800端口映射到docker容器的80端口中
--restart always # 宿主机重启自动拉起这个docker容器
挂载数据卷
docker run -it -v /宿主机绝对路径目录:/容器内目录 镜像名
docker run -it -v /myDataVolume:/dataVolumeContainer centos1
查看数据卷是否挂载成功,HostConfig.Binds数组中的内容就是挂载的数据卷
docker inspect efff311983951
(2)启动、停止
启动已停止的容器
docker start 容器id
停止(-d参数为后台运行)
docker stop <容器 ID>
重启
docker restart <容器 ID>
强制停止容器
docker kill 容器ID或容器名
(3)进入容器
/bin/bash
:不加时也默认有
docker exec -it 243c32535da7 /bin/bash
下面命令了解即可
docker attach 容器ID
attach 直接进入容器启动命令的终端,不会启动新的进程,用exit退出,会导致容器的停止。
exec 是在容器中打开新的终端,并且可以启动新的进程,用exit退出,不会导致容器的停止。
(4)退出容器
exit:exit退出,容器停止
ctrl+p+q:ctrl+p+q退出,容器不停止
(5)删除容器
docker rm -f 容器ID或容器名
(6)查看端口映射
docker port 容器ID或容器名
(7)查看日志
docker logs -f 容器ID或容器名
-f: 让 docker logs 像使用 tail -f 一样来输出容器内部的标准输出。
(8)查看容器进程
docker top 容器ID或容器名
(9)重命名
docker rename old_name new_name
(10)查看容器细节
docker inspect 容器ID
(11)查看容器资源使用情况
docker stats 容器ID
3、容器文件
(1)容器、主机拷贝文件
容器→主机
docker cp 容器ID:容器内路径 目的主机路径
主机→容器
docker cp 主机路径 容器ID:容器内路径
(2)容器备份
备份容器:export 导出容器的内容留作为一个tar归档文件[对应import命令]
docker export 容器ID > 文件名.tar
恢复备份:import 从tar包中的内容创建一个新的文件系统再导入为镜像[对应export]
下面语句是通过备份文件创建一个镜像
cat 文件名.tar | docker import - 镜像用户/镜像名:镜像版本号
(3)通过容器生成镜像
docker commit -m="提交的描述信息" -a="作者" 容器ID 要创建的目标镜像名:[标签名]
4、挂载数据卷
(1)概述
将 docker 容器中的目录和宿主机的目录进行绑定(可以理解为 vue 中的双向绑定)
- 宿主机中目录修改,容器也会修改
- 容器修改,宿主机目录也会修改
- 即使容器重启后,宿主机在此期间修改的文件也会同步
常用于容器数据的持久化,类似于 redis 的 rdb 或 aof
(2)如何挂载
运行一个带有容器卷存储功能的容器实例
docker run -it --privileged=true -v /宿主机绝对路径目录:/容器内目录 镜像名
查看数据卷是否挂载成功(查看Mounts数组下的数据)
docker inspect 容器ID
(3)读写权限
**读写(默认)rw **
rw 默认存在,写不写没区别
docker run -d --privileged=true -v /宿主机绝对路径目录:/容器内目录:rw 镜像名
只读 ro
容器实例内部被限制,只能读取不能写
docker run -d --privileged=true -v /宿主机绝对路径目录:/容器内目录:ro 镜像名
(4)卷的继承和共享
容器2继承容器1的卷规则
docker run -d --privileged=true --volumes-from 容器1名 --name 容器2名 镜像id
此时宿主机、容器1、容器2形成了三向绑定
(5)挂载文件无法实时共享
当使用vim之类的编辑器进行保存时,它不是直接保存文件,而是采用了备份、替换的策略。就是编辑时,创建了一个新文件,在保存的时候把备份文件替换为源文件,这个时候文件的inode就发生了变化,而原来indode对应的文件其实并没有修改,也就是容器内的文件没有变化。当重启容器的时候,会挂载新的inode.
解决方案:
1、避免直接挂载文件,而是挂载目录;
2、如果真要挂载文件,那么要将文件权限修改为777
chmod 777 sendFtpNew_111.sh
(6)解决无访问权限
Docker挂载主机目录访问如果出现cannot open directory .: Permission denied
解决办法:在挂载目录后多加一个–privileged=true参数即可
如果是CentOS7安全模块会比之前系统版本加强,不安全的会先禁止,所以目录挂载的情况被默认为不安全的行为,
在SELinux里面挂载目录被禁止掉了额,如果要开启,我们一般使用–privileged=true命令,扩大容器的权限解决挂载目录没有权限的问题,也即
使用该参数,container内的root拥有真正的root权限,否则,container内的root只是外部的一个普通用户权限。
三、发布镜像
1、阿里云
https://www.bilibili.com/video/BV1gr4y1U7CY?p=26
之后就可以在仓库中看到对应操作文档了
2、私有仓库
下载镜像Docker Registry
docker pull registry
运行私有仓库(默认情况,仓库被创建在容器的/var/lib/registry目录下,建议自行用容器卷映射,方便于宿主机联调)
docker run -d -p 5000:5000 -v /zzyyuse/myregistry/:/tmp/registry --privileged=true registry
curl验证私服库上有什么镜像
curl -XGET http://192.168.111.162:5000/v2/_catalog
修改镜像名
使用命令 docker tag 将zzyyubuntu:1.2 这个镜像(要发布到私服的镜像)修改为192.168.111.162:5000/zzyyubuntu:1.2
docker tag zzyyubuntu:1.2 192.168.111.162:5000/zzyyubuntu:1.2
允许http方式推送镜像
vim命令新增如下内容insecure-registries
:vim /etc/docker/daemon.json
{
"registry-mirrors": ["https://aa25jngu.mirror.aliyuncs.com"],
"insecure-registries": ["192.168.111.162:5000"]
}
别无脑照着复制,registry-mirrors 配置的是国内阿里提供的镜像加速地址,不用加速的话访问官网的会很慢。
上述理由:docker默认不允许http方式推送镜像,通过配置选项来取消这个限制。====> 修改完后如果不生效,建议重启docker
push推送到私服库
docker push 192.168.111.162:5000/zzyyubuntu:1.2
pull到本地并运行
docker pull 192.168.111.162:5000/zzyyubuntu:1.2
3、发布到Docker Hup
在 docker hup 网站登录,并创建仓库
服务器登录 docker hup 用户
docker login
- 利用
docker commit
命令生成镜像。
docker commit [OPTIONS] CONTAINER [REPOSITORY[:TAG]]
-a :提交的镜像作者
-m :提交时的说明文字
-p :在commit时,将容器暂停
-c :使用Dockerfile指令来创建镜像(在本场景中没有使用)
eg. docker commit -a "zhongliuzizai" -m "test" a404c6c174a2 username/ubuntu_java8:1.0.0
- 利用
docker images
命令查看镜像是否生成。
推送镜像
docker push 你的账号/镜像名称:TAG
四、Dockerfile
1、介绍
Dockerfile是用来构建Docker镜像的文本文件,是由一条条构建镜像所需的指令和参数构成的脚本。
其实 docker hup上面的所有的镜像都是可以看成由一个 DockerFile 生成的
构建三步骤:
- 编写Dockerfile文件
- docker build命令构建镜像
- docker run依镜像运行容器实例
基础知识:
- 1:每条保留字指令都必须为大写字母且后面要跟随至少一个参数
- 2:指令按照从上到下,顺序执行
- 3:#表示注释
- 4:每条指令都会创建一个新的镜像层并对镜像进行提交
Docker执行Dockerfile的大致流程
- (1)docker从基础镜像运行一个容器
- (2)执行一条指令并对容器作出修改
- (3)执行类似docker commit的操作提交一个新的镜像层
- (4)docker再基于刚提交的镜像运行一个新容器
- (5)执行dockerfile中的下一条指令直到所有指令都执行完成
案例:
FROM java:8
EXPOSE 8080
VOLUME /tmp
ADD renren-fast.jar /app.jar
RUN bash -c 'touch /app.jar'
ENTRYPOINT ["java","-jar","/app.jar"]
2、常用保留字
(1)FROM
基础镜像,当前新镜像是基于哪个镜像的,指定一个已经存在的镜像作为模板,第一条必须是from
FROM java:8
(2)MAINTAINER
镜像维护者的姓名和邮箱地址
(3)RUN
容器构建时需要运行的命令,即由 DockerFile 生成镜像时执行的命令,两种格式:
shell格式(直接写 linux 命令):
RUN <命令行命令>
RUN yum -y install vim
exec格式
RUN ["可执行文件","参数1","参数2"]
RUN ["./test.php","dev","offline"]
等价于
RUN ./test.php dev offline
案例:
ADD renren-fast.jar /app.jar
RUN bash -c 'touch /app.jar'
前面的ADD命令把jar复制过去,改名为app.jar
后面touch命令的作用是修改这个文件的访问时间和修改时间为当前时间,而不会修改文件的内容。
(4)EXPOSE
当前容器对外暴露出的端口
EXPOSE 8080
如果 EXPOSE 暴露的端口确定要和某个宿主机端口建立映射关系,还是要用到 docker run -p 参数
(5)WORKDIR
指定在创建容器后,终端默认登陆的进来工作目录,一个落脚点,默认是 /
WORKDIR /usr/mytest
workdir 最主要的目的是构建时不同层的镜像进到是同一个目录
(6)USER
指定该镜像以什么样的用户去执行,如果都不指定,默认是root
(7)ENV
用来在构建镜像过程中设置环境变量,即定义变量
ENV MY_PATH /usr/mytest
WORKDIR $MY_PATH
(8)VOLUME
容器数据卷,用于数据保存和持久化工作
VOLUME /tmp/
定义匿名数据卷。在启动容器时忘记挂载数据卷,会自动挂载到匿名卷。
作用:
- 避免重要的数据,因容器重启而丢失,这是非常致命的。
- 避免容器不断变大。
在启动容器 docker run 的时候,我们可以通过 -v 参数修改挂载点。
上述 VOLUME /tmp/ 定义的是容器内目录所在路径,在容器创建过程中会在容器中创建该目录,而宿主机上的挂载目录名是随机生成的,例如:
/var/lib/docker/volumes/593fda6d7b8296bfca22894b326727c734133eebb11c9bc2c25a73b892157a37
目录对应的就是容器中的 /tmp/ 目录
docker -v 可以指定挂载到宿主机的具体目录,相对于Dockerfile的 VOLUME 挂载方式更具有可控性
(9)COPY
类似ADD,拷贝文件和目录到镜像中。
将从构建上下文目录中 <源路径>
的文件/目录复制到新的一层的镜像内的 <目标路径>
位置
COPY src dest
或
COPY ["src", "dest"]
<src源路径>
:源文件或者源目录<dest目标路径>
:容器内的指定路径,该路径不用事先建好,路径不存在的话,会自动创建。
(10)ADD
将宿主机目录下的文件拷贝进镜像且会自动处理URL和解压tar压缩包,copy + 解压
ADD 指令和 COPY 的使用格类似(同样需求下,官方推荐使用 COPY)。功能也类似,不同之处如下:
- ADD 的优点:在执行
<源文件>
为 tar 压缩文件的话,压缩格式为 gzip, bzip2 以及 xz 的情况下,会自动复制并解压到<目标路径>
。 - ADD 的缺点:在不解压的前提下,无法复制 tar 压缩文件。会令镜像构建缓存失效,从而可能会令镜像构建变得比较缓慢。具体是否使用,可以根据是否需要自动解压来决定。
(11)CMD
指定容器启动后的要干的事情,Dockerfile 中可以有多个 CMD 指令,但只有最后一个生效,CMD 会被 docker run 之后的参数替换
CMD ["catalina.sh","run"]
如果通过 docker run 生成容器运行时,后面加了参数,例如下面的 /bin/bash
,则会导致CMD命令失效
docker run -it -p 8080:8080 镜像id /bin/bash
它和前面RUN命令的区别:
- CMD是在docker run 时运行(容器启动后)。
- RUN是在 docker build时运行(容器构建时)。
(12)ENTRYPOINT
也是用来指定一个容器启动时要运行的命令,类似于 CMD 指令,但是ENTRYPOINT不会被docker run后面的命令覆盖,而且这些命令行参数会被当作参数送给 ENTRYPOINT 指令指定的程序
但是, 如果运行 docker run 时使用了 –entrypoint 选项,将覆盖 ENTRYPOINT 指令指定的程序。
优点:在执行 docker run 的时候可以指定 ENTRYPOINT 运行所需的参数。
注意:如果 Dockerfile 中如果存在多个 ENTRYPOINT 指令,仅最后一个生效。
ENTRYPOINT ["<可执行文件或命令>","","",...]
可以搭配 CMD 命令使用:
一般是变参才会使用 CMD ,这里的 CMD 等于是在给 ENTRYPOINT 传参,以下示例会提到。
示例:假设已通过 Dockerfile 构建了 nginx:test 镜像:
FROM nginx
ENTRYPOINT ["nginx", "-c"] # 定参
CMD ["/etc/nginx/nginx.conf"] # 变参
1、不传参运行
docker run nginx:test
容器内会默认运行以下命令,启动主进程。
nginx -c /etc/nginx/nginx.conf
2、传参运行
docker run nginx:test -c /etc/nginx/new.conf
容器内会默认运行以下命令,启动主进程(/etc/nginx/new.conf:假设容器内已有此文件)
nginx -c /etc/nginx/new.conf
3、优化
注意:Dockerfile 的指令每执行一次都会在 docker 上新建一层。所以过多无意义的层,会造成镜像膨胀过大。例如:
FROM centos
RUN yum -y install wget
RUN wget -O redis.tar.gz "http://download.redis.io/releases/redis-5.0.3.tar.gz"
RUN tar -xvf redis.tar.gz
以上执行会创建 3 层镜像。可简化为以下格式:
FROM centos
RUN yum -y install wget \
&& wget -O redis.tar.gz "http://download.redis.io/releases/redis-5.0.3.tar.gz" \
&& tar -xvf redis.tar.gz
如上,以 && 符号连接命令,这样执行后,只会创建 1 层镜像。
4、build 命令
docker build [OPTIONS] PATH | URL | -
选项
- **–build-arg=[] :**设置镜像创建时的变量;
- **–cpu-shares :**设置 cpu 使用权重;
- **–cpu-period :**限制 CPU CFS周期;
- **–cpu-quota :**限制 CPU CFS配额;
- **–cpuset-cpus :**指定使用的CPU id;
- **–cpuset-mems :**指定使用的内存 id;
- **–disable-content-trust :**忽略校验,默认开启;
- **-f :**指定要使用的Dockerfile路径;
- **–force-rm :**设置镜像过程中删除中间容器;
- **–isolation :**使用容器隔离技术;
- **–label=[] :**设置镜像使用的元数据;
- **-m :**设置内存最大值;
- **–memory-swap :**设置Swap的最大值为内存+swap,”-1”表示不限swap;
- **–no-cache :**创建镜像的过程不使用缓存;
- **–pull :**尝试去更新镜像的新版本;
- **–quiet, -q :**安静模式,成功后只输出镜像 ID;
- **–rm :**设置镜像成功后删除中间容器;
- **–shm-size :**设置/dev/shm的大小,默认值是64M;
- **–ulimit :**Ulimit配置。
- **–squash :**将 Dockerfile 中所有的操作压缩为一层。
- –tag, -t: 镜像的名字及标签,通常 name:tag 或者 name 格式;可以在一次构建中为一个镜像设置多个标签。
- –network: 默认 default。在构建期间设置RUN指令的网络模式
案例
使用当前目录的 Dockerfile 创建镜像,标签为 runoob/ubuntu:v1。
docker build -t runoob/ubuntu:v1 .
使用URL github.com/creack/docker-firefox 的 Dockerfile 创建镜像。
docker build github.com/creack/docker-firefox
也可以通过 -f Dockerfile 文件的位置:
docker build -f /path/to/a/Dockerfile .
5、使用步骤
- 编写 Dockerfile 文件
- 构建镜像(在 Dockerfile 同目录下),注意,上面TAG后面有个空格,有个点
docker build -t 新镜像名字:TAG .
- 运行
docker run -it 新镜像名字:TAG
6、java微服务Dockerfile
Dockerfile 内容
# 基础镜像使用java
FROM java:8
# 作者
MAINTAINER zzyy
#暴露6001端口作为微服务
EXPOSE 6001
# VOLUME 指定临时文件目录为/tmp,在主机/var/lib/docker目录下创建了一个临时文件并链接到容器的/tmp
VOLUME /tmp
# 将jar包添加到容器中并更名为zzyy_docker.jar
ADD docker_boot-0.0.1-SNAPSHOT.jar zzyy_docker.jar
# 运行jar包
RUN bash -c 'touch /zzyy_docker.jar'
ENTRYPOINT ["java","-jar","/zzyy_docker.jar"]
将微服务jar包和Dockerfile文件上传到同一个目录下,执行一下命令构建镜像
docker build -t zzyy_docker:1.6 .
运行容器
docker run -d -p 6001:6001 zzyy_docker:1.6
即可访问微服务
五、Docker 网络
1、概念
容器网络实质上是由 Docker 为应用程序所创造的虚拟环境的一部分,它能让应用从宿主机操作系统的网络环境中独立出来,形成容器自有的网络设备、IP 协议栈、端口套接字、IP 路由表、防火墙等与网络相关的模块。
即在 linux 服务器中,启动 Docker 后,可用 ifconfig
命令看到新增了一个 Docker0
虚拟网桥
作用:
- 保证容器间的互联和通信以及端口映射
- 不同服务器docker容器之间的访问,容器IP变动时(docker重启)可以通过服务名直接网络通信而不受到影响
2、基本命令
(1)查看所有网络
docker network ls
默认创建以下三大网络模式,DRIVER
从上到下,常用 - 偶尔用 - 基本不用
NETWORK ID NAME DRIVER SCOPE
8861516133fe bridge bridge local
7d756a9587ee host host local
4a18823ee223 none null local
(2)创建新网络
创建的网络默认是 bridge
模式
docker network create 新网络名
(3)删除指定网络
docker network rm 网络名
(4)删除未使用网络
docker network prune
(5)查看指定网络详情
docker network inspect 网络名
3、网络模式
四种网络模式
网络模式 | 配置 | 说明 |
---|---|---|
bridge | –net=bridge | 为每一个容器分配、设置 IP 等,并将容器连接到 docker0 虚拟网桥上,默认模式 |
host | –net=host | 容器不会创建自己的网卡,配置 IP 等,而是使用宿主机的 IP 和端口 |
container | –net=container:NAME_or_ID | 容器不会创建自己的网卡,配置 IP 等,而是和一个指定的容器共享 IP和端口 |
none | –net=none | 关闭网络功能,不进行任何网络设置 |
修改容器运行的网络模式只需要在执行 docker run
时,增加 --network 网络模式
即可
docker run -d --network host --name tomcat tomcat镜像
(1)bridge
Docker 服务默认会创建一个 docker0 网桥(其上有一个 docker0 内部接口),该桥接网络的名称为docker0,它在内核层连通了其他的物理或虚拟网卡,这就将所有容器和本地主机都放到同一个物理网络。Docker 默认指定了 docker0 接口 的 IP 地址和子网掩码,让主机和容器之间可以通过网桥相互通信。
详细说明
1、Docker
使用 Linux
桥接,在宿主机虚拟一个 Docker
容器网桥 (docker0)
,Docker
启动一个容器时会根据 Docker
网桥的网段分配给容器一个IP地址,称为 Container-IP
,同时 Docker
网桥是每个容器的默认网关。因为在同一宿主机内的容器都接入同一个网桥,这样容器之间就能够通过容器的 Container-IP
直接通信。
2、docker run
的时候,没有指定 network
的话默认使用的网桥模式就是 bridge
,使用的就是 docker0
。在宿主机 ifconfig
,就可以看到 docker0
和自己 create
的 network
(后面讲)eth0,eth1,eth2……代表网卡一,网卡二,网卡三……,lo代表127.0.0.1,即localhost,inet addr用来表示网卡的IP地址
3、网桥 docker0
创建一对对等虚拟设备接口一个叫 veth
,另一个叫 eth0
,成对匹配。
- 3.1 整个宿主机的网桥模式都是docker0,类似一个交换机有一堆接口,每个接口叫veth,在本地主机和容器内分别创建一个虚拟接口,并让他们彼此联通(这样一对接口叫veth pair);
- 3.2 每个容器实例内部也有一块网卡,每个接口叫eth0;
- 3.3 docker0上面的每个veth匹配某个容器实例内部的eth0,两两配对,一一匹配。
通过上述,将宿主机上的所有容器都连接到这个内部网络上,两个容器在同一个网络下,会从这个网关下各自拿到分配的ip,此时两个容器的网络是互通的。
(2)host
直接使用宿主机的 IP 地址与外界进行通信,不再需要额外进行NAT 转换。
容器将不会获得一个独立的Network Namespace, 而是和宿主机共用一个Network Namespace。容器将不会虚拟出自己的网卡而是使用宿主机的IP和端口。
使用该模式时,端口映射选项 -p 没有任何意义,端口号会以主机端口号为主,重复时则递增。
(3)none
在none模式下,并不为Docker容器进行任何网络配置。 也就是说,这个Docker容器没有网卡、IP、路由等信息,只有一个lo,需要我们自己为Docker容器添加网卡、配置IP等。
基本不用
(4)container
新建的容器和已经存在的一个容器共享一个网络ip配置而不是和宿主机共享。新创建的容器不会创建自己的网卡,配置自己的IP,而是和一个指定的容器共享IP、端口范围等。同样,两个容器除了网络方面,其他的如文件系统、进程列表等还是隔离的。
(5)自定义网络
解决问题:不同容器之间只能使用 ip 进行访问,容器重启后 ip 可能发生变化,导致无法访问
自定义网络默认使用的是桥接网络bridge
自定义网络步骤:
- 新建自定义网络
docker network create 自定义网络名
- 新建容器加入上一步新建的自定义网络
docker run -d -p 8081:8080 --network 自定义网络名 --name tomcat81 billygoo/tomcat8-jdk8
docker run -d -p 8082:8080 --network 自定义网络名 --name tomcat82 billygoo/tomcat8-jdk8
- 可通过容器名进行互相访问
ping tomcat81
....
六、Compose服务编排
1、概念
Compose
是 Docker 公司推出的一个工具软件,可以管理多个 Docker 容器组成一个应用。你需要定义一个 YAML 格式的配置文件 docker-compose.yml
,写好多个容器之间的调用关系。然后,只要一个命令,就能同时启动/关闭这些容器
可以很容易地用一个配置文件定义一个多容器的应用,然后使用一条指令安装这个应用的所有依赖,完成构建。Docker-Compose 解决了容器与容器之间如何管理编排的问题。
官网
https://docs.docker.com/compose/compose-file/compose-file-v3/
官网下载
https://docs.docker.com/compose/install/
2、安装
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
卸载
rm /usr/local/bin/docker-compose
3、常用命令
docker-compose -h # 查看帮助
docker-compose up # 启动所有docker-compose服务
docker-compose up -d # 启动所有docker-compose服务并后台运行
docker-compose -f my.yml up # 指定yml文件
docker-compose down # 停止并删除容器、网络、卷、镜像。
docker-compose exec yml里面的服务id # 进入容器实例内部 docker-compose exec docker-compose.yml文件中写的服务id /bin/bash
docker-compose ps # 展示当前docker-compose编排过的运行的所有容器
docker-compose top # 展示当前docker-compose编排过的容器进程
docker-compose logs yml里面的服务id # 查看容器输出日志
docker-compose config # 检查配置
docker-compose config -q # 检查配置,有问题才有输出
docker-compose restart # 重启服务
docker-compose start # 启动服务
docker-compose stop # 停止服务
(1)启动docker-compose
docker-compose up命令可以自动完成包括构建镜像,(重新)创建服务,启动服务,并关联服务相关容器的一系列操作。在 docker-compose.yml
同级目录下执行
docker-compose up [options] [--scale SERVICE=NUM...] [SERVICE...]
命令参数解释:
-d 在后台运行服务容器
–no-color 不使用颜色来区分不同的服务的控制输出
–no-deps 不启动服务所链接的容器
–force-recreate 强制重新创建容器,不能与–no-recreate同时使用
–no-recreate 如果容器已经存在,则不重新创建,不能与–force-recreate同时使用
–no-build 不自动构建缺失的服务镜像
–build 在启动容器前构建服务镜像
–abort-on-container-exit 停止所有容器,如果任何一个容器被停止,不能与-d同时使用
-t, –timeout TIMEOUT 停止容器时候的超时(默认为10秒)
–remove-orphans 删除服务中没有在compose文件中定义的容器
–scale SERVICE=NUM 设置服务运行容器的个数,将覆盖在compose中通过scale指定的参数
4、使用步骤
docker-compose.yml
# compose 的版本
version: "3"
# 容器实例集合,
services:
# 自定义服务名,必须与其他的不冲突,每个服务相当于一个 docker run 命令
microService:
# 镜像名
image: zzyy_docker:1.6
# 容器名,如果没有指定,默认是 文件夹名_服务名_序号
container_name: ms01
# 端口映射
ports:
- "6001:6001"
# 数据卷
volumes:
- /app/microService:/data
# docker 网络,在最下面定义
networks:
- atguigu_net
# 此服务依赖的其他服务
depends_on:
- redis
- mysql
redis:
image: redis:6.0.8
ports:
- "6379:6379"
volumes:
- /app/redis/redis.conf:/etc/redis/redis.conf
- /app/redis/data:/data
networks:
- atguigu_net
command: redis-server /etc/redis/redis.conf
mysql:
image: mysql:5.7
environment:
MYSQL_ROOT_PASSWORD: '123456'
MYSQL_ALLOW_EMPTY_PASSWORD: 'no'
MYSQL_DATABASE: 'db2021'
MYSQL_USER: 'zzyy'
MYSQL_PASSWORD: 'zzyy123'
ports:
- "3306:3306"
volumes:
- /app/mysql/db:/var/lib/mysql
- /app/mysql/conf/my.cnf:/etc/my.cnf
- /app/mysql/init:/docker-entrypoint-initdb.d
networks:
- atguigu_net
command: --default-authentication-plugin=mysql_native_password #解决外部无法访问
# 创建 docker 网络,相当于下面的语句
# dcoker network create atguigu_net
networks:
atguigu_net:
服务之间通过服务名调用,例如下面 springboot 的 mysql 和 redis 连接
#spring.datasource.url=jdbc:mysql://192.168.111.169:3306/db2021?useUnicode=true&characterEncoding=utf-8&useSSL=false
# 修改如下
spring.datasource.url=jdbc:mysql://mysql:3306/db2021?useUnicode=true&characterEncoding=utf-8&useSSL=false
#spring.redis.host=192.168.111.169
# 修改如下
spring.redis.host=redis
将 jar 包、Dockerfile、docker-compose.yml 上传到服务器同一文件夹,并 cd 到对应目录
因为 microService
使用了 Dockerfile 所以需要先执行 (如果 compose 中的服务没用到 Dockerfile 可不执行)
docker build -t zzyy_docker:1.6 .
检查 docker-compose.yml
编写语法是否出错,有问题才会有输出
docker-compose config -q
然后执行服务编排
docker-compose up -d
七、Portainer可视界面
1、安装
Portainer 是一款轻量级的应用,它提供了图形化界面,用于方便地管理Docker环境,包括单机环境和集群环境。
https://docs.portainer.io/v/ce-2.9/start/install/server/docker/linux
安装:
docker run -d -p 8000:8000 -p 9000:9000 --name portainer \
--restart=always \
-v /var/run/docker.sock:/var/run/docker.sock \
-v portainer_data:/data \
portainer/portainer
如果使用 https 则映射 9443
访问:http://宿主机ip:9000/
创建用户
选择local
八、容器监控 CIG
1、介绍
通过docker stats命令可以很方便的看到当前宿主机上所有容器的CPU,内存以及网络流量等数据,一般小公司够用了。但是,docker stats统计结果只能是当前宿主机的全部容器,数据资料是实时的,没有地方存储、没有健康指标过线预警等功能
CIG
指的是三个软件,CAdvisor监控收集+InfluxDB存储数据+Granfana展示图表
(1)CAdvisor监控收集
CAdvisor
是一个容器资源监控工具,包括容器的内存,CPU,网络IO,磁盘IO等监控,同时提供了一个WEB页面用于查看容器的实时运行状态。CAdvisor默认存储2分钟的数据,而且只是针对单物理机。不过CAdvisor
提供了很多数据集成接口,支持InfluxDB
,Redis
,Kafka
,Elasticsearch
等集成(官方推荐的是InfluxDB)。可以加上对应配置将监控数据发往这些数据库存储起来。
功能主要有两点:
- 展示Host和容器两个层次的监控数据
- 展示历史变化数据。
(2)InfluxDB存储数据
InfluxDB是用Go语言编写的一个开源分布式时序、事件和指标数据库,无需外部依赖。
CAdvisor默认旨在本机保存最近2分钟的数据,为了持久化存储数据和统一收集展示监控数据,需要将数据存储到InfluxDB中。InfluxDB是一个时序数据库,专门用于存储时序相关数据,很适合CAdvisor的数据。而且,CAdvisor本身已经提供了InfluxDB的集成方法,启动容器时指定配置即可。
InfluxDB主要功能:
- 基于时间序列,支持与时间有关的相关函数(如最大,最小,求和等)
- 可度量性:你可以实时对大量数据进行计算
- 基于事件:它支持任意的事件数据
(2)Granfana展示图表
Granfana是一个开源的数据监控分析可视化平台,支持多种数据源配置和丰富的插件及模板功能,支持图表权限控制和报警
主要特性:
- 灵活丰富的图形化选项
- 可以混合多种风格
- 支持白天和夜间模式
- 多个数据源
2、安装
新建目录 /mydocker/cig
在目录下新建 docker-compose.yml
内容如下
version: '3.1'
volumes:
grafana_data: {}
services:
influxdb:
image: tutum/influxdb:0.9
restart: always
environment:
- PRE_CREATE_DB=cadvisor
ports:
- "8083:8083"
- "8086:8086"
volumes:
- ./data/influxdb:/data
cadvisor:
image: google/cadvisor
links:
- influxdb:influxsrv
command: -storage_driver=influxdb -storage_driver_db=cadvisor -storage_driver_host=influxsrv:8086
restart: always
ports:
- "8080:8080"
volumes:
- /:/rootfs:ro
- /var/run:/var/run:rw
- /sys:/sys:ro
- /var/lib/docker/:/var/lib/docker:ro
grafana:
user: "104"
image: grafana/grafana
user: "104"
restart: always
links:
- influxdb:influxsrv
ports:
- "3000:3000"
volumes:
- grafana_data:/var/lib/grafana
environment:
- HTTP_USER=admin
- HTTP_PASS=admin
- INFLUXDB_HOST=influxsrv
- INFLUXDB_PORT=8086
- INFLUXDB_NAME=cadvisor
- INFLUXDB_USER=root
- INFLUXDB_PASS=root
执行 docker-compose up
启动完成
浏览cAdvisor收集服务,http://ip:8080/
浏览influxdb存储服务,http://ip:8083/
浏览grafana展现服务,http://ip:3000
九、查看容器的构建命令
1、安装runlike
安装Python-pip
yum -y install python-pip
安装runlike
pip install runlike
我在linux安装时报错:
Command "python setup.py egg_info" failed with error code 1 in /tmp/pip-build-jWgv5b/click/
You are using pip version 8.1.2, however version 22.1.2 is available
You should consider upgrading via the 'pip install --upgrade pip' command
按照提示运行
pip install --upgrade pip
如果还是不行,先看自己本地python版本,选择下面对应版本升级pip
# 升级pip:
sudo wget https://bootstrap.pypa.io/pip/2.7/get-pip.py
sudo python get-pip.py
pip -V
# 升级pip3:
sudo wget https://bootstrap.pypa.io/pip/3.5/get-pip.py
sudo python3 get-pip.py
pip -V
没有问题后再安装runlike
pip install runlike
2、使用
runlike -p 容器
[15:51:20][root@yuanian-61-186:~]# runlike -p nginx
docker run \
--name=nginx \
--hostname=328f219d6fd2 \
--mac-address=02:42:ac:11:00:02 \
--env=PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin \
--env=NGINX_VERSION=1.17.0 \
--env=NJS_VERSION=0.3.2 \
--env='PKG_RELEASE=1~stretch' \
--volume=/data/deploy/nginx/data:/usr/share/nginx/html \
--volume=/data/deploy/nginx/conf:/etc/nginx \
-p 8080:8080 \
-p 443:443 \
--expose=80 \
--restart=unless-stopped \
--label='maintainer=NGINX Docker Maintainers ' \
--log-opt max-size=5m \
--detach=true \
192.168.48.90/common/nginx:1.17.0 \
nginx -g 'daemon off;'