DockerFile
DockerFile是什么?
- Dockerfile是用来构建Docker镜像的文本文件,是由一条条构建镜像所需的指令和参数构成的脚本。
镜像构建三大步:
- 编写DockerFile文件
- 执行docker build 命令构建镜像
- docker run 运行容器。
DockerFile构建过程解析
Dockerfile内容基础知识
- 每条保留字指令都必须为大写字母且后面要跟随至少一个参数
- 指令按照从上到下,顺序执行
- #表示注释
- 每条指令都会创建一个新的镜像层并对镜像进行提交
Docker执行Dockerfile的大致流程
Docker基于最开始的镜像,创建运行一个容器,根据一条命令对容器进行修改,然后Docker commit提交一层镜像层,然后有基于这个镜像层,创建新的容器,然后有根据下一条命令修改容器,然后又提交,直至最后一条命令执行完。
DockerFile常用保留字指令
From : 基础镜像,当前镜像是基于哪个镜像的,必须指定基础镜像,DockerFile第一条命令必须是From
MAINTAINER : 镜像维护者姓名邮箱
RUN : 镜像构建时需要运行的Linux命令,Run是在docker build的时候执行的
--shell格式: RUN yum install xxx(运行一条yum命令)
--exec格式: RUN [可执行文件,参数1,参数2] # 例:RUN [./redis-server,/etc/redis/redis.conf] 等同于 RUN ./redis-server /etc/redis/redis.conf
EXPOSE : 镜像构建完成,运行当前镜像,生成的容器对外暴露的端口
WORKDIR : 指的是在运行容器时,进入交互终端所在的文件目录
USER : 指定镜像 需要什么用户才能执行 默认Root
ENV : 构建过程中设置环境变量
ADD : 将宿主机中的文件添加到容器中,会自动的解压tar压缩包和自动处理URL
COPY : 将宿主机中的文件拷贝到容器中 (类似于ADD 但是不会自动解压,)# COPY ["src", "dest"]
VOLUME : 容器卷
CMD : 指定容器启动后要干的事情(和前面RUN的区别:Run在Build时运行,CMD在容器运行后运行)
--shell格式:CMD yum install xxx(运行一条yum命令)
--exec格式: CMD [可执行文件,参数1,参数2],
--Dockerfile 中可以有多个 CMD 指令,但只有最后一个生效,CMD 会被 docker run 之后的参数替换
ENTRYPOINT : 类似于 CMD 指令,但是ENTRYPOINT不会被docker run后面的命令覆盖,
---而且这些命令行参数会被当作参数送给 ENTRYPOINT 指令指定的程序
---如果 Dockerfile 中如果存在多个 ENTRYPOINT 指令,仅最后一个生效。
编写一个Dockerfile文件(centos7+java8)
FROM centos:7 #基础镜像centos 7
MAINTAINER zzyy<zzyybs@126.com>
ENV MYPATH /usr/local# 设置环境变量
WORKDIR $MYPATH# 设置工作目录
#安装vim编辑器
RUN yum -y install vim #运行 yum 命令
#安装ifconfig命令查看网络IP
RUN yum -y install net-tools
#安装java8及lib库
RUN yum -y install glibc.i686
RUN mkdir /usr/local/java
#ADD 是相对路径jar,把jdk-8u171-linux-x64.tar.gz添加到容器中,安装包必须要和Dockerfile文件在同一位置
ADD jdk-8u171-linux-x64.tar.gz /usr/local/java/#将java8文件添加到容器并且解压
#配置java环境变量
ENV JAVA_HOME /usr/local/java/jdk1.8.0_171
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 #设置PATH环境变量
EXPOSE 80 暴露端口
CMD echo $MYPATH
CMD echo "success--------------ok"
CMD /bin/bash
编译Dockerfile文件
docker build -t 镜像名:TAG . #记住最后又一个点
新的镜像
Docker微服务实战
简单使用Docker发布微服务项目
打包微服务项目(记得加打包插件,不然会报没有主属性清单)
插件:
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
编写DockerFile
ROM java:8 #
VOLUME /tmp
RUN mkdir -p /myjar/jar
ADD demo.jar /myjar/jar/demo.jar #将Demo.jar 放到目录下
ENTRYPOINT ["java","-jar","/myjar/jar/demo.jar"] #运行jar包
EXPOSE 8000 #对外暴露8000端口
运行容器
docker run -d -p 8000:8000 boot:1.0
就打包好了。
Docker网络
Docker网络的基本命令
查看网络
docker network ls
创建网络
docker network create 网络名
查看网络数据
docker network inspect
删除网络
docker network rm 网络名
Docker网络模式
-
bridge模式:使用–network bridge指定,默认使用docker0
-
host模式:使用–network host指定
-
none模式:使用–network none指定
-
container模式:使用–network container:NAME或者容器ID指定
容器实例内默认网络IP生产规则
容器默认使用的是桥接模式。Docker每次启动容器时,容器内部的IP都是会变化的。
Bridge(桥接模式)
- Docker 服务默认会创建一个 docker0 网桥(其上有一个 docker0 内部接口),该桥接网络的名称为docker0,它在内核层连通了其他的物理或虚拟网卡,这就将所有容器和本地主机都放到同一个物理网络。Docker 默认指定了 docker0 接口 的 IP 地址和子网掩码,让主机和容器之间可以通过网桥相互通信。
说明
- 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地址
- 网桥docker0创建一对对等虚拟设备接口一个叫veth,另一个叫eth0,成对匹配。
- 整个宿主机的网桥模式都是docker0,类似一个交换机有一堆接口,每个接口叫veth,在本地主机和容器内分别创建一个虚拟接口,并让他们彼此联通(这样一对接口叫veth pair);
- 每个容器实例内部也有一块网卡,每个接口叫eth0;
- docker0上面的每个veth匹配某个容器实例内部的eth0,两两配对,一一匹配。
通过上述,将宿主机上的所有容器都连接到这个内部网络上,两个容器在同一个网络下,会从这个网关下各自拿到分配的ip,此时两个容器的网络是互通的。
验证两两对应
HOST模式
- 直接使用宿主机的 IP 地址与外界进行通信,不再需要额外进行NAT 转换。
- 容器将不会获得一个独立的Network Namespace, 而是和宿主机共用一个Network Namespace。容器将不会虚拟出自己的网卡而是使用宿主机的IP和端口。
会出什么问题?
因为是复用的宿主机的IP和端口,所以在启动容器时的端口映射也就没有意义了
docker run -d -p 8083:8080 --network host --name tomcat83 billygoo/tomcat8-jdk8 #运行这段代码会产生警告
原因:
docker启动时指定–network=host或-net=host,如果还指定了-p映射端口,那这个时候就会有此警告,
并且通过-p设置的参数将不会起到任何作用,端口号会以主机端口号为主,重复时则递增。
docker run -d -p 8083:8080 --name tomcat83 billygoo/tomcat8-jdk8 #这样就没问题了
none模式
禁用网络功能,只有lo标识(就是127.0.0.1表示本地回环)
container模式
新建的容器和已经存在的一个容器共享一个网络ip配置而不是和宿主机共享。新创建的容器不会创建自己的网卡,配置自己的IP,而是和一个指定的容器共享IP、端口范围等。同样,两个容器除了网络方面,其他的如文件系统、进程列表等还是隔离的。
注意: 使用这个模式因为共用一个IP和端口,两个容器的端口不能冲突,比如两个tomcat就不能使用这个模式
docker run -it --network container:alpine1 --name alpine2 alpine /bin/sh #启动另一个alpine,并且,使用容器alpine1的IP和端口
自定义网络
如果我们使用默认的bridge模式,是不能通过容器名相互ping的,进入之前创建的boot容器中。pring java:8这个容器是不能够ping通的。所以我们需要自定义网络
创建网络
docker network create 网络名
docker会再次虚拟一块网卡出来,这里不再使用默认的docker0网卡:
注意:Linux为了安全起见,多于一块网卡的时候会禁用IPV4的转发,会导致外网不能连接 docker内部的服务
所以我们需要开启IPV4的转发
vim /etc/sysctl.conf
#配置转发
net.ipv4.ip_forward=1
#保存退出就可以了
:wq!
#重启服务,让配置生效
systemctl restart network
新建容器加入上一步新建的自定义网络
docker run -it --network custome --name cent2 centos:7 /bin/bash #创建cent2
docker run -it --network custome --name cent3 centos:7 /bin/bash #创建cent3
互相ping测试
为什么自定义网络能通过服务名Ping通呢?
自定义网络本身就维护好了主机名和ip的对应关系(ip和域名都能通)
Docker容器编排
是什么?
- Compose 是 Docker 公司推出的一个工具软件,可以管理多个 Docker 容器组成一个应用。你需要定义一个 YAML 格式的配置文件docker-compose.yml,写好多个容器之间的调用关系。然后,只要一个命令,就能同时启动/关闭这些容器
去哪下载
官网:https://docs.docker.com/compose/compose-file/compose-file-v3/(指导使用)
官网下载:https://docs.docker.com/compose/install/(下载)
安装Docker compose
执行下面的命令
curl -SL https://github.com/docker/compose/releases/download/v2.4.1/docker-compose-linux-x86_64 -o /usr/local/lib/docker/cli-plugins/docker-compose #从Github下载可执行二进制文件
chomd +x /usr/local/lib/docker/cli-plugins/docker-compose #将可执行权限应用于二进制文件:
检验是否安装好了
docker compose version
卸载Docker compose
rm -f /usr/local/lib/docker/cli-plugins/docker-compose
Compose核心概念
一文件:docker-compose.yml
两要素:
- 服务(service)
- 一个个应用容器实例,比如订单微服务、库存微服务、mysql容器、nginx容器或者redis容器
- 工程(project)
- 由一组关联的应用容器组成的一个完整业务单元,在 docker-compose.yml 文件中定义。
Compose使用的三个步骤
- 编写Dockerfile定义各个微服务应用并构建出对应的镜像文件
- 使用 docker-compose.yml 定义一个完整业务单元,安排好整体应用中的各个容器服务。
- 最后,执行docker-compose up命令 来启动并运行整个应用程序,完成一键部署上线
Docker compose 常用命令
docker-compose -h # 查看帮助
docker-compose up # 启动所有docker-compose服务
docker-compose up -d # 启动所有docker-compose服务并后台运行
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 # 查看容器输出日志
dokcer-compose config # 检查配置
dokcer-compose config -q # 检查配置,有问题才有输出
docker-compose restart # 重启服务
docker-compose start # 启动服务
docker-compose stop # 停止服务
使用Compose
第一步: 打包微服务(使用Dockerfile生成镜像)
# 基础镜像使用java
FROM java:8
# 作者
MAINTAINER zzyy
# VOLUME 指定临时文件目录为/tmp,在主机/var/lib/docker目录下创建了一个临时文件并链接到容器的/tmp
VOLUME /tmp
# 将jar包添加到容器中并更名为zzyy_docker.jar
ADD docker_boot-0.0.1-SNAPSHOT.jar dockertest.jar
# 运行jar包
RUN bash -c 'touch /dockertest.jar'
ENTRYPOINT ["java","-jar","/dockertest.jar"]
#暴露6001端口作为微服务
EXPOSE 6001
第二步:编写docker-compose.yml
version: "3"
services:
microService: #名字
image: zzyy_docker:1.6 #微服务镜像
container_name: ms01
ports:
- "6001:6001"
volumes:
- /app/microService:/data
networks:
- atguigu_net #加入自定义网络
depends_on: #代表在这个镜像容器启动前先启动的
- redis
- mysql
redis:
image: redis:6.0.8 #Redis镜像
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 #comman选项
mysql:
image: mysql:5.7
environment:
MYSQL_ROOT_PASSWORD: '123456'
MYSQL_ALLOW_EMPTY_PASSWORD: 'no'
MYSQL_DATABASE: 'db2021'
MYSQL_USER: 'user'
MYSQL_PASSWORD: '123456'
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 #解决外部无法访问
networks: #创建网络
atguigu_net:
第三步:执行DockerCompose
docker compose up
踩坑:
Service的字母写错了
IPV4的转发被禁止了,外网不能访问docker 所以需要修改
vim /etc/sysctl.conf
#配置转发
net.ipv4.ip_forward=1
#保存退出就可以了
:wq!
#重启服务,让配置生效
systemctl restart network
运行成功
第一次运行,docker中不存在容器,先创建容器
第二次运行:docker中存在容器了 直接运行
Docker轻量可视化工具Portainer
是什么?
Portainer 是一款轻量级的应用,它提供了图形化界面,用于方便地管理Docker环境,包括单机环境和集群环境。
官网:https://www.portainer.io/
官网文档:https://docs.portainer.io/v/ce-2.9/start/install/server/docker/linux
Portainer安装
docker run -d -p 8000:8000 -p 9443:9443 -p 9000:9000 --name portainer \
--restart=always \
-v /var/run/docker.sock:/var/run/docker.sock \
-v portainer_data:/data \
portainer/portainer-ce:2.9.3
–restart =always 代表 随着docker启动而启动,docker停止而停止
第一次登录需创建admin,访问地址:xxx.xxx.xxx.xxx:9000
- 用户名,直接用的默认admin
密码记得8位,随便你写
设置admin用户和密码后首次登陆
选择local选项卡后本地docker详细信息展示
对应的Docker命令是
docker system df
Docker容器监控之CAdvisor+InfluxDB+Granfana
原生命令
docker stats #查看docker容器状况
CAdvisor+InfluxDB+Granfana是什么?
一句话:CAdvisor监控收集+InfluxDB存储数据+Granfana展示图表
总结
启动三剑客
使用docker compose一套带走
编写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文件
docker compose up
访问CAdvisor
http://IP:8080 ##第一次访问要收集数据可能会有点慢
- cadvisor也有基础的图形展现功能,这里主要用它来作数据采集
浏览influxdb存储服务
http://IP:8083
浏览grafana展现服务
http://IP:3000 #默认账号密码 admin admin
配置Grafanan步骤
- 配置数据源
-
选择influxdb数据源
-
配置细节
- 配置面板panel
- 到这里cAdvisor+InfluxDB+Grafana容器监控系统就部署完成了