2024-07-31
Docker
00

目录

DockerFile解析
DockerFile构建过程解析
Dockerfile常用保留字指令
案例
Docker微服务实战
Docker网络
bridge模式
host模式
none模式
container模式
自定义网络
Docker-compose容器编排
Docker容器监控
可视化工具Portainer
CAdvisor+InfluxDB+Granfan监控

DockerFile解析

是什么?

Dockerfile是用来构建Docker镜像的文本文件,是由一条条构建镜像所需的指令和参数构成的脚本

构建三步骤

  1. 编写DockerFile文件
  2. docker build命令构建镜像
  3. docker run依镜像运行容器实例

DockerFile构建过程解析

Dockerfile内容基础知识:

  1. 每条保留字指令都必须为大写字母且后面要跟随至少一个参数
  2. 指令按照从上到下的顺序执行
  3. #表示注释
  4. 每条指令都会创建一个新的镜像层并对镜像进行提交

Docker执行Dockerfile大致流程

  1. docker从基础镜像运行一个容器

  2. 执行一条指令并对容器作出修改

  3. 执行类似 docker commit 的操作提交一个新的镜像层

  4. docker再基于刚提交的镜像运行一个新容器

  5. 执行dockerfile中的下一条指令直到所有指令都执行完成

小总结

从应用软件的角度来看,Dockerfile、Docker镜像与Docker容器分别代表软件的三个不同阶段

  • Dockerfile是软件的原材料

  • Docker镜像是软件的交付品

  • Docker容器则可以认为是软件镜像的运行态,也即依照镜像运行的容器实例

Dockerfile面向开发,Docker镜像成为交付标准,Docker容器则涉及部署与运维,三者缺一不可,合力充当Docker体系的基石。

  1. Dockerfile,需要定义一个Dockerfile,Dockerfile定义了进程需要的一切东西。Dockerfile涉及的内容包括执行代码或者是文件、环境变量、依赖包、运行时环境、动态链接库、操作系统的发行版、服务进程和内核进程(当应用进程需要和系统服务和内核进程打交道,这时需要考虑如何设计namespace的权限控制)等等;
  2. Docker镜像,在用Dockerfile定义一个文件之后,docker build时会产生一个Docker镜像,当运行Docker镜像时会真正开始提供服务;
  3. Docker容器,容器是直接提供服务的。

Dockerfile常用保留字指令

保留字描述
FROM基础镜像,当前新镜像是基于哪个镜像的,指定一个已经存在的镜像作为模板,第一条必须是FROM
MAINTAINFR镜像维护者的姓名和邮箱地址
RUN容器构建时需要运行的命令,一种shell格式,一种exec格式,RUN是在 docker build 时运行的
EXPOSE当前容器对外暴露出的端口
WORKDIR指定在创建容器后,终端默认登陆的进来工作目录,一个落脚点
USER指定该镜像以什么样的用户去执行,如果都不指定,默认是root
ENV用来在构建镜像过程中设置环境变量
ADD将宿主机目录下的文件拷贝进镜像且会自动处理URL和解压tar压缩包
COPY类似ADD,拷贝文件和目录到镜像中,将从构建上下文目录中<源路径>的文件/目录复制到新的一层的镜像内的<目标路径>位置
VOLUME容器数据卷,用于数据保存和持久化工作
CMD指定容器启动后要干的事情,CMD指令也有shell和exec两种格式,Dockerfile中可以有多个CMD指令,但只有最后一个生效,CMD会被 docker run 之后的参数替换,CMD是在 docker run 时运行,RUN是在 docker build 时运行
ENTRYPOINT也是用来指定一个容器启动时要运行的命令,类似于CMD指令,但是ENTRYPOINT不会被docker run后面的命令覆盖,而且这些命令行参数会被当做参数送给ENTRYPOINT指令指定的程序

案例

一、自定义镜像mycentosajva8

  • 要求:centos镜像具备 vim+ifconfig+jdk8,在jdk官网下载jdk-8u411-linux-x64.tar.gz

  • 编写:编写Dockerfile文件,首字母D需要大写,编辑文件:vim Dockerfile

    bash
    FROM centos:7.9.2009 MAINTAINER jerry<[email protected]> ENV MYPATH /usr/local WORKDIR $MYPATH # 安装命令之前,先修改yum源 RUN cd /etc/yum.repos.d/ RUN sed -i 's/mirrorlist/#mirrorlist/g' /etc/yum.repos.d/CentOS-* RUN sed -i 's|#baseurl=http://mirror.centos.org|baseurl=http://vault.centos.org|g' /etc/yum.repos.d/CentOS-* RUN yum update -y # 安装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-8u411-linux-x64.tar.gz 添加到容器中,安装包必须要和Dockerfile文件在同一位置 ADD jdk-8u411-linux-x64.tar.gz /usr/local/java # 配置java环境变量 ENV JAVA_HOME /usr/local/java/jdk1.8.0_411 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
  • 构建:docker build -t 新镜像名字:TAG .,注意TAG后面有个空格和一个点,示例:docker build -t centosjava8:1.0 .

  • 运行:docker run -it centosjava8:1.0 /bin/bash

二、虚悬镜像

是什么:仓库名、标签名都是<none>的镜像,俗称dangling image。

bash
# 新建一个 Dockerfile # vim Dockerfile FROM ubuntu CMD echo "action is success" # 构建镜像 docker build . # 查看镜像 docker images # 新构建的镜像仓库和标签都是 <none>,这个就是虚悬镜像 REPOSITORY TAG IMAGE ID CREATED SIZE <none> <none> da3244bb7207 4 weeks ago 78.1MB

查看虚悬镜像

bash
docker image ls -f dangling=true

删除虚悬镜像

bash
docker image prune

Docker微服务实战

把java项目打包一个jar包

通过dockerfile发布微服务部署到docker容器

bash
# 编辑Dockerfile文件,vim Dockerfile # 基础镜像使用java FROM openjdk:8 # 作者 MAINTAINER jerry # VOLUME 指定临时文件目录为/tmp,在主机/var/lib/docker目录下创建了一个临时文件并链接到容器的/tmp VOLUME /tmp # 将jar包添加到容器中并更改名为 app.jar ADD Java-1.0-SNAPSHOT.jar app.jar # 运行jar包 RUN bash -c "touch /app.jar" ENTRYPOINT ["java","-jar","/app.jar"]

构建镜像:docker build -t app:1.0 .

运行容器:docker run -d app:1.0

Docker网络

安装完docker后,默认会创建3个网络模式,docker容器内部的ip是有可能发生变化的

bash
[root@localhost ~]# docker network ls NETWORK ID NAME DRIVER SCOPE 8b829941e2ed bridge bridge local c3fac193d510 host host local 37a0dd9a3074 none null local

常用基本命令

  • 创建一个新虚拟网络:docker network create 网络名字

    bash
    docker network create a_network
  • 删除docker中的虚拟网络:docker network rm 网络名字

    bash
    docker network rm a_network
  • 查看网络源数据:docker network inspect 网络名字

    bash
    docker network inspect bridge

能干嘛?

  • 容器间的互联和通讯以及端口映射
  • 容器IP变动时候可以通过服务名直接网络通讯而不受到影响

网络模式

网络模式描述
bridge为每一个容器分配、设置IP等,并将容器连接到一个docker0,虚拟网桥,默认为该模式。
host容器将不会虚拟出自己的网卡,配置自己的IP等,而是使用宿主机的IP和端口。
none容器独有的 Network namespace,但并没有对其进行任何网络设置,如分配 veth pair 和网桥连接,IP等。
container新创建的容器不会创建自己的网卡和配置自己的IP,而是和一个指定的容器共享IP,端口范围等。

bridge模式:使用--network bridge指定,默认使用docker0

host模式:使用--network host指定

none模式:使用--network none指定

container模式:使用--network container:NAME或容器ID指定

Docker服务默认会创建一个docker0网桥(其上有一个dockero0内部接口),该桥接网络的名称为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模式

先运行两个tomcat

bash
docker run -d -p8081:8080 --name tomcat81 tomcat docker run -d -p8082:8080 --name tomcat82 tomcat

在宿主机使用ip addr命令查看网卡信息

宿主机38: vethff59bb6@if37网卡对应的容器内的eth0@if38

宿主机40: vetha888fe1@if39网卡对应的容器内的39: eth0@if40

bash
38: vethff59bb6@if37: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default link/ether 7e:93:04:92:4f:30 brd ff:ff:ff:ff:ff:ff link-netnsid 0 inet6 fe80::7c93:4ff:fe92:4f30/64 scope link valid_lft forever preferred_lft forever 40: vetha888fe1@if39: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default link/ether 06:bc:8c:ae:25:29 brd ff:ff:ff:ff:ff:ff link-netnsid 1 inet6 fe80::4bc:8cff:feae:2529/64 scope link valid_lft forever preferred_lft forever

进入其中一个容器执行ip addr命令

bash
39: eth0@if40: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default link/ether 02:42:ac:11:00:03 brd ff:ff:ff:ff:ff:ff link-netnsid 0 inet 172.17.0.3/16 brd 172.17.255.255 scope global eth0 valid_lft forever preferred_lft forever

进入另一个容器查看

bash
37: eth0@if38: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0 inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0 valid_lft forever preferred_lft forever

host模式

直接使用宿主机的IP地址与外界通讯,不再额外进行NAT转换。

docker启动时指定 --network=host 或 -net=host,如果还指定了-p映射端口,那这个时候就会有警告,并且通过-p设置的参数将不会起到任何作用,端口号会以主机端口号为主,重复时则递增。

在宿主机查看网络配置和进入容器查看网络配置是几乎一样的

bash
docker run -d -p 8083:8080 --network host --name tomcat83 tomcat # 使用 --network host 模式时可以不写-p参数 docker run -d --network host --name tomcat83 tomcat

none模式

禁用网络功能,只有lo标识(就是127.0.0.1表示本地回环),在none模式下,并不为docker容器进行任何网络配置

bash
docker run -d -p 8084:8080 --network none --name tomcat84 tomcat

container模式

新建的容器和已经存在的一个容器共享一个网络ip配置而不是和宿主机共享。新创建的容器不会创建自己的网卡,配置自己的IP,而是和一个指定的容器共享IP、端口范围等。同样,两个容器除了网络方面,其他的如文件系统、进程列表等还是隔离的

如果已经存在容器挂掉了,新建的容器网络配置就没有共享的配置了

bash
docker run -it --name alpine1 alpine /bin/sh docker run -it --network container:alpine1 --name alpine2 alpine /bin/sh

自定义网络

自定义网络本身就维护好了主机名和ip的对应关系(ip和域名都能通)

先启动2个容器

bash
docker run -d -p 8081:8080 --name tomcat81 tomcat docker run -d -p 8082:8080 --name tomcat82 tomcat

进入2个容器

bash
docker exec -it tomcat82 /bin/bash docker exec -it tomcat81 /bin/bash

按照IP地址ping是通的

bash
root@86ef8f36808a:/usr/local/tomcat# ping 172.17.0.3 PING 172.17.0.3 (172.17.0.3) 56(84) bytes of data. 64 bytes from 172.17.0.3: icmp_seq=1 ttl=64 time=0.059 ms 64 bytes from 172.17.0.3: icmp_seq=2 ttl=64 time=0.049 ms 64 bytes from 172.17.0.3: icmp_seq=3 ttl=64 time=0.050 ms

因为ip地址有可能变化,所以按照服务名ping,但是默认ping不通

bash
root@86ef8f36808a:/usr/local/tomcat# ping tomcat82 ping: tomcat82: Name or service not known

自定义桥接网络,自定义网络默认使用的桥接网络bridge

新建自定义网络

bash
docker network create test_network

新建容器加入自定义网络

bash
docker run -d -p 8081:8080 --network test_network --name tomcat81 tomcat docker run -d -p 8082:8080 --network test_network --name tomcat82 tomcat

互相ping测试,ping服务名就可以ping通了

bash
root@f38210b7ed22:/usr/local/tomcat# ping tomcat82 PING tomcat82 (172.19.0.2) 56(84) bytes of data. 64 bytes from tomcat82.test_network (172.19.0.2): icmp_seq=1 ttl=64 time=0.130 ms 64 bytes from tomcat82.test_network (172.19.0.2): icmp_seq=2 ttl=64 time=0.037 ms

Docker-compose容器编排

docker-compose 是Docker官方的开源项目,负责实现对Docker容器集群的快速编排

Compose是Docker公司推出的一个工具软件,可以管理多个Docker容器组成一个应用。你需要定义一个YAML格式的配置文件docker-compose.yml,写好多个容器之间的调用关系。然后,只要一个命令,就能同时启动/关闭这些容器,docker-compose解决了容器与容器之间如何编排的问题。

下载安装

bash
# 下载安装docker-compose curl -L "https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose # 给应用加上执行权限 chmod +x /usr/local/bin/docker-compose # 查看版本 docker-compose --version

compose使用的三个步骤

编写Dockerfile定义各个微服务应用并构建出对应的镜像文件

使用docker-compose.yml定义一个完整业务单元,安排好整体应用中的各个容器服务

执行docker-compose up命令来启动并运行整个应用程序,完成一键部署上线

常用命令

命令描述
docker-compose -h查看帮助
docker-compose up启动所有docker-compose服务
docker-compose up -d启动所有docker-compose服务并后台运行
docker-compose down停止并删除容器、网络、卷、镜像
docker-compose exec 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停止服务

案例演示

编写docker-compose.yml文件,启动之前,先把mysql和redis的配置文件编辑好。

bash
version: "3" services: microService: image: app:1.0 container_name: ms01 ports: - "6001:6001" volumes: - /data/microService:/data networks: - app_net depends_on: - redis - mysql redis: image: redis:6.0.8 ports: - "6379:6379" volumes: - /data/redis/redis.conf:/etc/redis/redis.conf - /data/redis/data:/data networks: - app_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: 'app' MYSQL_USER: 'dev' MYSQL_PASSWORD: 'dev123456' ports: - "3306:3306" volumes: - /data/mysql/db:/var/lib/mysql - /data/mysql/conf/my.cnf:/etc/my.cnf - /data/mysql/init:/docker-entrypoint-initdb.d networks: - app_net command: --default-authentication-plugin=mysql_native_password #解决外部无法访问 networks: app_net:

编辑完docker-compose.yml文件后,我们可以直接运行:docker-compose up -d命令启动

Docker容器监控

可视化工具Portainer

Portainer 是一款轻量级的应用,它提供了图形化界面,用于方便地管理Docker环境,包括单机环境和集群环境。

安装,--restart=always参数表示docker重启的话,portainer也会重启

bash
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

CAdvisor+InfluxDB+Granfan监控

通过docker stats命令可以很方便的看到当前宿主机上所有容器的CPU,内存以及网络流量等数据,但是docker stats统计结果只能是当前宿主机的全部容器,数据资料是实时的,没有地方存储,没有健康指标线预警等功能。

CAdvisor是监控收集

CAdvisor是一个容器资源监控工具包括容器的内存,CPU,网络IO,磁盘IO等监控,同时提供了一个WEB页面用于查看容器的实时运行状态。CAdvisor默认存储2分钟的数据,而且只是针对单物理机。不过,CAdvisor提供了很多数据集成接口,支持InfluxDB, Redis, Kafka, Elasticsearch等集成,可以加上对应配置将监控数据发往这些数据库存储起来。

CAdvisor功能主要有2点

  • 展示Host和容器两个层次的监控数据
  • 展示历史变化数据

InfluxDB存储数据

InfluxDB是用Go语言编写的一个开源分布式时序、事件和指标数据库,无需外部依赖。

CAdvisor默认只在本机保存最近2分钟的数据,为了持久化存储数据和统一收集展示监控数据,需要将数据存储到InfluxDB中。InfluxDB是一个时序数据库,专门用于存储时序相关数据,很适合存储CAdvisor的数据。而且,CAdvisor本身已经提供了InfluxDB的集成方法,启动容器时指定配置即可。

nfluxDB主要功能

  • 基于时间序列,支持与时间有关的相关函数(如最大、最小、求和等)
  • 可度量性:你可以实时对大量数据进行计算
  • 基于事件:它支持任意的事件数据

Granfana展示图表

Grafana是一个开源的数据监控分析可视化平台,支持多种数据源配置(支持的数据源包括InfluxDB, MySQL, Elasticsearch, OpenTSDB, Graphite等)和丰富的插件及模板功能,支持图表权限控制和报警。

Grafana主要特性

  • 灵活丰富的图形化选项
  • 可以混合多种风格
  • 支持白天和黑夜模式
  • 多个数据源

docker-compose.yml容器编排

bash
version: '3.1' volumes: grafana_data: {} services: influxdb: image: tutum/influxdb 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 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 -d命令启动

cAdvisor收集服务,http://ip:8080/

influxdb存储服务,http://ip:8083/

grafana展现服务,http://ip:3000/

第一次访问grafana服务,需要输入账号密码,默认账号密码都是admin,默认influxdb的数据库账号密码也都是root

本文作者:柯南

本文链接:

版权声明:©2024 柯南 All rights reserved.