3 Docker微服务实战

3.1 通过IDEA新建一个普通微服务模块

建Module
docker_boot
改POM

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.6</version>
<relativePath/>
</parent>

<groupId>com.atguigu.docker</groupId>
<artifactId>docker_boot</artifactId>
<version>0.0.1-SNAPSHOT</version>

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<junit.version>4.12</junit.version>
<log4j.version>1.2.17</log4j.version>
<lombok.version>1.16.18</lombok.version>
<mysql.version>5.1.47</mysql.version>
<druid.version>1.1.16</druid.version>
<mapper.version>4.1.5</mapper.version>
<mybatis.spring.boot.version>1.3.0</mybatis.spring.boot.version>
</properties>

<dependencies>
<!--SpringBoot通用依赖模块-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!--test-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<version>3.1.0</version>
</plugin>
</plugins>
</build>

</project>

写YML
server.port=6001
主启动

1
2
3
4
5
6
7
8
9
10
11
12
13
14
package com.atguigu.docker;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class DockerBootApplication
{
public static void main(String[] args)
{
SpringApplication.run(DockerBootApplication.class, args);
}

}

业务类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
package com.atguigu.docker.controller;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import java.util.UUID;

/**
* @auther zzyy
* @create 2021-10-25 17:43
*/
@RestController
public class OrderController
{
@Value("${server.port}")
private String port;

@RequestMapping("/order/docker")
public String helloDocker()
{
return "hello docker"+"\t"+port+"\t"+ UUID.randomUUID().toString();
}

@RequestMapping(value ="/order/index",method = RequestMethod.GET)
public String index()
{
return "服务端口号: "+"\t"+port+"\t"+UUID.randomUUID().toString();
}
}

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

IDEA工具里面搞定微服务jar包
docker_boot-0.0.1-SNAPSHOT.jar
image.png
编写Dockerfile

1
2
3
4
5
6
7
8
9
10
11
12
13
# 基础镜像使用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 zzyy_docker.jar
# 运行jar包
RUN bash -c 'touch /zzyy_docker.jar'
ENTRYPOINT ["java","-jar","/zzyy_docker.jar"]
#暴露6001端口作为微服务
EXPOSE 6001

:::info
将微服务jar包和Dockerfile文件上传到同一个目录下/mydocker
image.png
docker build -t zzyy_docker:1.6 .
:::
构建镜像
:::info
docker build -t zzyy_docker:1.6 .
打包成镜像文件
image.png
:::
运行容器
docker run -d -p 6001:6001 zzyy_docker:1.6
image.png
访问测试
image.png

4 Docker网络

是什么

docker不启动,默认网络情况
image.png

在Docker服务启动前,使用 ifconfigip addr 查看网卡信息:

  • ens33eth0:本机网卡
  • lo:本机回环网络网卡
  • 可能有virbr0(CentOS安装时如果选择的有相关虚拟化服务,就会多一个以网桥连接的私网地址的virbr0网卡,作用是为连接虚拟网卡提供NAT访问外网的功能。如果要移除该服务,可以使用 yum remove libvirt-libs.x86_64

使用 systemctl start docker启动Docker服务后,会多出一个 docker0 网卡。

作用:

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

Docker容器的网络隔离,是通过Linux内核特性 namespacecgroup 实现的。

docker启动后,网络情况
会产生一个名为docker0的虚拟网桥
image.png
查看docker网络模式命令,默认创建3大网络模式。
image.png

常用基本命令

All命令
image.png
查看网络
docker network ls

添加Docker网络:
docker network add xxx

查看网络源数据
docker network inspect XXX网络名字

删除网络
docker network rm XXX网络名字
案例
image.png

能干嘛

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

网络模式

总体介绍
image.png
:::info
bridge模式:使用–network bridge指定,默认使用docker0
host模式:使用–network host指定
none模式:使用–network none指定
container模式:使用–network container:NAME或者容器ID指定
:::
容器实例内默认网络IP生产规则
:::info

  1. 先启动两个ubuntu容器实例

image.png

  1. docker inspect 容器ID or 容器名字

  2. 通过inspect获取容器信息,最后20行即为容器的网络模式信息

image.png

  1. 关闭u2实例,新建u3,查看ip变化

image.png
:::
结论
docker容器内部的ip是有可能会发生改变的

docker0

Docker 服务默认会创建一个docker0网桥(其上有一个docker0内部接口),该桥接网络的名称为 docker0,它在内核层连通了其他的物理或虚拟网卡,这就将所有容器和本地主机都放到同一个物理网络。

Docker默认指定了docker0 接口的IP地址和子网掩码,让主机和容器之间可以通过网桥互相通信。

查看bridge网络的详细信息,并通过 grep获取名称:

1
2
docker network inspect bridge | grep name

可以看到其名称为docker0。

bridge模式

Docker使用Linux桥接,在宿主机虚拟一个Docker容器网桥(docker0),Docker启动一个容器时会根据Docker网桥的网段分配给容器一个IP地址,称为Container-IP,同时Docker网桥是每个容器的默认网关。因为在同一个宿主机内的容器接入同一个网桥,这样容器之间就能够通过容器的Container-IP直接通信。

docker run的时候,没有指定--network的话,默认使用的网桥模式就是bridge,使用的就是docker0。在宿主机ifconfig就苦役看到docker0和自己create的network。

网桥 docker0创建一对对等虚拟设备接口,一个叫veth,另一个叫eth0,成对匹配:

整个宿主机的网桥模式都是docker0,类似一个交换机有一堆接口,每个接口叫 veth,在本地主机和容器内分别创建一个虚拟接口,并让他们彼此联通(这样一对接口叫做 veth pair)。

每个容器实例内部也有一块网卡,容器内的网卡接口叫做eth0。

docker0上面的每个veth匹配某个容器实例内部的eth0,两两配对,一一匹配。

例如:

启动tomcat容器,进入tomcat容器后,执行 ip addr,可以看到其网卡信息:

1
2
3
4
5
1: lo ..................

容器内的网卡为 eth0
@符号后面就是宿主机上对应的veth网卡的编号28
27: eth0@if28 ...............................

**host模式

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

容器将不会获得一个独立的 Network Namespace,而是和宿主机共用一个 Network space。

容器将不会虚拟出自己的网卡,而是直接使用宿主机的 IP 和端口。

如果在 docker run 命令中同时使用了 --network host-p端口映射,例如:

1
docker run -p 8082:8080 --network host tomcat

那么会出现一个警告:

1
WARNING: Published ports are discarded when using host network mode

因为此时已经使用了host模式,本身就是直接使用的宿主机的IP和端口,此时的-p端口映射就没有了意义,也不会生效,端口号还是会以主机端口号为主。

正确做法是:不再进行-p端口映射,或者改用bridge模式

none模式

禁用网络功能。

在none模式下,并不为docker容器进行任何网络配置。进入容器内,使用 ip addr查看网卡信息,只能看到 lo(本地回环网络127.0.0.1网卡)。

container模式

新建的容器和已经存在的一个容器共享网络IP配置,而不是和宿主机共享。

新创建的容器不会创建自己的网卡、IP,而是和一个指定的容器共享IP、端口范围。两个容器除了网络共享,其他的如文件系统、进程列表依然是隔离的。

示例:

1
2
3
4
docker run -it --name alpine1 alpine /bin/sh

# 指定和 alpine1 容器共享网络
docker run -it --netrowk container:alpine1 --name alpine2 alpine /bin/sh

此时使用 ip addr查看两台容器的网络,会发现两台容器的eth0网卡内的IP等信息完全相同。

如果关掉了alpine1容器,因为alpine2的网络使用的alpine1共享网络,所以关掉alpin1后,alpine2的eth0网卡也随之消失了。

自定义网络(常用)

容器间的互联和通信以及端口映射。

容器 IP 变动时候可以通过服务名直接网络通信而不受影响。(类似Eureka,通过服务名直接互相通信,而不是写死IP地址)。

docker中还有一个 --link 进行容器网络互联,但是已经被标记为过时的,可能会在将来的版本中移除这个功能。推荐使用自定义网络替换link。

自定义桥接网络(自定义网络默认使用的是桥接网络 bridge):

1 新建自定义网络

1
docker network create tomcat_network

2 查看网络列表

1
docker network ls

3 创建容器时,指定加入我们自定义的网络中

1
2
docker run -d-p8081:8080 --network tomcat_network --name tomcat1 tomcat:8.5-jdk8-corretto
docker run -d-p8082:8080 --network tomcat_network --name tomcat2 tomcat:8.5-jdk8-corretto

4 此时进入tomcat1中,使用ping命令测试连接tomcat2容器名,发现可以正常连通

1
2
3
4
5
6
7
8
# 安装ifconfig命令
yum install -y net-tools
# 安装ip addr命令
yum install -y iproute
# 安装ping命令
yum install -y iputils
# 直接ping容器名,不需要ping IP地址
ping tomcat2

link连接

示例:

1
2
3
4
5
6
7
8
# 启动一台mysql容器
# --name 为容器指定一个别名
docker run --name mysql-matomo -p3308:3306 -eMYSQL_ROOT_PASSWORD=root -d mysql:8.0.28
# 启动另一个容器,通过--link连接到mysql容器
# --link 容器名称:本容器连接对方时的别名
docker run -d-p8888:80 --link mysql-matomo:db --name matomo matomo:4.9.0
# 此时,在matomo容器中,便可以通过 db 这个hostname连接到mysql-matomo容器,而无须再通过ip
# 连接地址:db:3306

Docker平台架构图解

整体说明
:::info
从其架构和运行流程来看,Docker 是一个 C/S 模式的架构,后端是一个松耦合架构,众多模块各司其职。
Docker 运行的基本流程为:
1 用户是使用 Docker Client 与 Docker Daemon 建立通信,并发送请求给后者。
2 Docker Daemon 作为 Docker 架构中的主体部分,首先提供 Docker Server 的功能使其可以接受 Docker Client 的请求。
3 Docker Engine 执行 Docker 内部的一系列工作,每一项工作都是以一个 Job 的形式的存在。
4 Job 的运行过程中,当需要容器镜像时,则从 Docker Registry 中下载镜像,并通过镜像管理驱动 Graph driver将下载镜像以Graph的形式存储。
5 当需要为 Docker 创建网络环境时,通过网络管理驱动 Network driver 创建并配置 Docker 容器网络环境。
6 当需要限制 Docker 容器运行资源或执行用户指令等操作时,则通过 Execdriver 来完成。
7 Libcontainer是一项独立的容器管理包,Network driver以及Exec driver都是通过Libcontainer来实现具体对容器进行的操作。
:::
整体架构
image.png

5 Docker-compose容器编排

Docker-compose

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

Docker-Compose可以管理多个Docker容器组成一个应用。需要定义一个yaml格式的配置文件 docker-compose.yml,配置好多个容器之间的调用关系,然后只需要一个命令就能同时启动/关闭这些容器。

Docker建议我们每个容器中只运行一个服务,因为Docker容器本身占用资源极少,所以最好是将每个服务单独的分割开来。但是如果我们需要同时部署多个服务,每个服务单独构建镜像构建容器就会比较麻烦。所以 Docker 官方推出了 docker-compose 多服务部署的工具。

Compose允许用户通过一个单独的 docker-compose.yml 模板文件来定义一组相关联的应用容器为一个项目(project)。可以很容易的用一个配置文件定义一个多容器的应用,然后使用一条指令安装这个应用的所有依赖,完成构建。

核心概念:

  • 服务(service):一个个应用容器实例
  • 工程(project):由一组关联的应用容器组成的一个完整业务单元,在docker-compose.yml中定义

Compose使用的三个步骤:

  1. 编写 Dockerfile 定义各个应用容器,并构建出对应的镜像文件
  2. 编写 docker-compose.yml,定义一个完整的业务单元,安排好整体应用中的各个容器服务
  3. 执行 docker-compose up 命令,其创建并运行整个应用程序,完成一键部署上线

安装Docker-Compose

Docker-Compose的版本需要和Docker引擎版本对应,可以参照官网上的对应关系

安装Compose:

1
2
3
4
5
6
7
8
9
# 例如从github下载 2.5.0版本的docker-compose
# 下载下来的文件放到 /usr/local/bin目录下,命名为 docker-compose
curl -L https://github.com/docker/compose/releases/download/v2.5.0/docker-compose-$(uname -s)-$(uname -m) -o /usr/local/bin/docker-compose

# 添加权限
chmod +x /usr/local/bin/docker-compose

# 验证
docker-compose version

卸载Compose:直接删除 usr/local/bin/docker-compose文件即可

常用命令

执行命令时,需要在对应的docker-compose.yml文件所在目录下执行。

查看帮助:

1
docker-compose -h

创建并启动docker-compose服务:(类似 docker run

1
2
3
4
docker-compose up

# 后台运行
docker-compose up -d

停止并删除容器、网络、卷、镜像:(类似 docker stop +  docker rm

1
docker-compose down

进入容器实例内部:

1
docker-compose exec <yml里面的服务id> /bin/bash

展示当前docker-compose编排过的运行的所有容器:

1
docker-compose ps

展示当前docker-compose编排过的容器进程:

1
docker-compose top

查看容器输出日志:

1
docker-compose log <yml里面的服务id>

检查配置:

1
2
3
4
docker-compose config

# 有问题才输出
docker-compose config -q

重启服务:

1
docker-compose restart

启动服务:(类似 docker start

1
docker-compose start

停止服务:

1
docker-compose stop

compose编排实例

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
# docker-compose文件版本号
version: "3"

# 配置各个容器服务
services:
microService:
image: springboot_docker:1.0
container_name: ms01 # 容器名称,如果不指定,会生成一个服务名加上前缀的容器名
ports:
- "6001:6001"
# - 80 只写一个,表示容器内部,主机端口随机映射
volumes:
- /app/microService:/data
networks:
- springboot_network
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:
- springboot_network
command: redis-server /etc/redis/redis.conf

mysql:
image: mysql:5.7
environment:
MYSQL_ROOT_PASSWORD: '123456'
MYSQL_ALLOW_EMPTY_PASSWORD: 'no'
MYSQL_DATABASE: 'db_springboot'
MYSQL_USER: 'springboot'
MYSQL_PASSWORD: 'springboot'
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:
- springboot_network
command: --default-authentication-plugin=mysql_native_password # 解决外部无法访问

networks:
# 创建 springboot_network 网桥网络
springboot_network:

编写完成docker-compose.yml后,进行语法检查:

1
2
# 进行语法检查
docker-compose config -q

如果语法检查没有任何问题,进行创建、启动:

1
docker-compose up -d

6 Docker轻量级可视化工具Portainer

是什么

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

安装

官网
https://www.portainer.io/
https://docs.portainer.io/v/ce-2.9/start/install/server/docker/linux
步骤

  1. docker命令安装
1
2
3
4
5
6
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
  1. 第一次登录需创建admin,访问地址:xxx.xxx.xxx.xxx:9000
    :::info
    用户名,直接用默认admin
    密码记得8位,随便你写
    image.png
    :::

  2. 设置admin用户和密码后首次登陆

image.png

  1. 选择local选项卡后本地docker详细信息展示

image.png

  1. 上一步的图形展示,能想得起对应命令吗?

image.png

登陆并演示介绍常用操作case

7 Docker容器监控之 CAdvisor+InfluxDB+Granfana

8 终章の总结

知识回顾简单串讲和总结
image.png
进阶篇:雷丰阳老师的K8S