微服务必备容器化技术

news2024/10/6 4:01:13

文章目录

  • docker介绍与安装及上手应用
    • 什么是容器化技术?为什么需要学习docker?
    • 如何理解docker
    • docker下载与安装
    • docker的基础组成
    • docker体验
  • dockerfile介绍并创建go-zero环境容器
    • docker的基础组成
    • 从容器构建属于go环境的容器
    • 基于dockerfile构建go容器镜像
    • 通过容器运行go-zero
    • 基于打包部署
    • 小结
  • docker-compose编排
    • 容器网络
    • docker容器互通
    • 部署api/rpc服务通讯
    • docker-compose
    • 总结

docker介绍与安装及上手应用

什么是容器化技术?为什么需要学习docker?

在微服务的体系架构中,因为应用程序会进行拆分,这时就会存在多个服务需要部署运行,相应的多个服务之间具有多种部署方案,这时传统的方式就会面临巨大的挑战。

在特殊时候需要动态的并快速的新增服务或减少服务,例如在秒杀抢购服务在双十一的时候才具有较大的并发流量,流量可能是平时的好几倍需要做好扩容,但是在平时又不存在这么多的流量,因此对整个程序就需要做到自适应伸缩扩容。

就有提出采用虚拟化技术,其代表的产品如VMWare,但是该方案存在问题,就是系统的启动运行需要较长的时间,因此在当时业界就希望有一种轻量级的虚拟化技术来解决这个问题,顾就提出了容器化技术。

容器化技术是一种轻量级的虚拟化技术,它利用操作系统级别的虚拟化来隔离应用程序和它们的依赖。容器化技术使用容器引擎(如Docker)来创建和管理容器,每个容器都运行在共享的操作系统内核上,可以共享主机的资源,而目前容器化技术中docker被广为熟知。

如何理解docker

在我们做项目的时候原本我们是定义为,一个应用程序对应 一个系统。

现在改为:

应用程序  → 特定的docker容器 → 部署到系统中

如下是docker的图标,一条鲸鱼+N个集装箱,实际上这个图标就已经很好的告诉我们docker的寓意和应用

图片描述

docker可以理解为是一个应用程序环境的打包运行工具,比如我们运行redis所依赖的核心程序一起打包成一个封装的独立的集中箱,然后通过docker可以移植部署在不同的环境系统上。这样在部署上就得到了统一,提高了开发和运维的交互效率。

而docker除了这样的功能外,它呢在容器启动停止的时候也是非常快速的,这样的话如果服务需要在某一个时候动态伸缩服务的时候就可以得到解决。

总结docker主要实现的功能

  1. 更高效的利用系统资源
  2. 更快速的启动时间
  3. 一致的运行环境
  4. 持续交付和部署
  5. 更轻松的迁移
  6. 更轻松的维护和扩展

docker下载与安装

# 安装依赖
yum install -y yum-utils device-mapper-persistent-data lvm2
# 添加软件源信息
yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
# 更新并安装Docker-CE --- 可以跳过不执行
yum makecache fast

yum list docker-ce --showduplicates|sort -r
# 默认安装最新版本
yum -y install docker-ce
# 配置docker镜像源和cgroup
mkdir /etc/docker/
touch /etc/docker/daemon.json
cat > /etc/docker/daemon.json << EOF
{
    "exec-opts": ["native.cgroupdriver=systemd"],
    "registry-mirrors": ["https://hub-mirror.c.163.com"]
}
EOF
systemctl enable  docker --now

docker system prune

docker的基础组成

图片描述

  • 宿主机:docker本质就是一个程序,它运行在那个系统上,那个系统就是它的宿主机
  • 容器:一个容器就是一个小的微型系统只有开发需要的依赖可以是运行也可以是非运行的状态
  • 镜像:如果想要创建容器就需要一个镜像,而所谓的镜像可以看成是一份编译好的代码程序,可以这么理解。准确一点理解是一个只读的模板,一个独立的文件系统,包括运行容器所需的数据,可以用来创建新的容器。
  • 仓库:和GitHub/gitee类似,只不过它上面存放的是镜像,你的镜像根文件就是来源这里,当然我们也可以自己发布自己的镜像

dockerfile: 镜像文件的代码版本,我可以通过编写代码创建想要的镜像。

docker体验

docker安装完成后,在命令行执行docker,如果能够看到命令提示则说明docker安装成功。我们可以通过通过doker创建一个安装好redis的容器。

仓库地址:hub.docker.com

# docker pull 是从仓库上下载容器; 在pull后则就是具体要下载的容器对象
docker pull redis:alpine3.18

# docker images 查看系统的镜像
docker images

# 通过docker run 运行启动
docker run -p 16379:6379 --name=redis -d redis:alpine3.18

# docker ps 查看正在运行的容器, 后跟 -a 则查询所有的包含停止的容器
docker ps 

解释:docker run帮助我们在宿主机中创建一个redis的容器,这个容器呢可谓是“麻雀虽小五脏俱全”在容器中会运行一个系统可以是centos也可以是ubuntu.当前我们使用的是一个叫alpine的系统,比centos和ubuntu要小。

图片描述
接下来看看docker run后面的命令参数-p 16379:6379 --name=redis -d redis:alpine3.18

  • 最后一个redis:alpine3.18 基本是固定的写法,即容器镜像,也就是docker pull 后指定的内容
  • -d 表示运行方式,我们让容器处于后台运行,而不是挂起在当前的命令行下运行
  • –name 指创建的容器名称,当前指定容器的名称为redis
  • -p 用于绑定容器与宿主机的端口,也就是第一个参数是属于宿主机的第二个属于容器的,也就是当我们访问16379的时候就会访问到redis容器的6379端口的服务。

dockerfile介绍并创建go-zero环境容器

docker的基础组成

图片描述

  • 宿主机:docker本质就是一个程序,它运行在那个系统上,那个系统就是它的宿主机
  • 容器:一个容器就是一个小的微型系统只有开发需要的依赖,可以是运行也可以是非运行的状态
  • 镜像:如果想要创建容器就需要一个镜像,而所谓的镜像可以看成是一份编译好的代码程序,可以这么理解。准确一点理解是一个只读的模板,一个独立的文件系统,包括运行容器所需的数据,可以用来创建新的容器。
  • 仓库:和GitHub/gitee类似,只不过它上面存放的是镜像,当然我们也可以自己发布自己的镜像
  • dockerfile: 镜像文件的代码版本,我可以通过编写代码创建想要的镜像。

从容器构建属于go环境的容器

在dockerfile的学习中遇到过很多的同学对其概念以及dockerfile构建中存在的问题,及dockerfile的运行本质并不是很了解,因此在学习dockerfile前,我们先自己通过以存在的容器构建go环境的容器。

过程:

  1. 选择好要构建go容器环境的系统
  2. 先拉取系统镜像
  3. 然后运行系统镜像,构建出容器
  4. 再进入容器安装go

选择好要构建go容器环境的系统

系统的选择很讲究,因为对docker来说,它是依托于宿主机运行的,同时我们也希望它能够启动运行足够快并且还期望它不占用太多的系统资源,顾选择较小的系统就有这块的优势。

这里我们用alpine系统作为go环境的运行系统,因为它比较小,大约7M的左右。

先拉取系统镜像

docker pull alpine:3.18

然后运行系统镜像,构建出容器

docker run -p 8080:80 --name go -d alpine:3.18

在构建容器的时候与宿主机绑定8080端口,可便于后续容器构建好之后的测试

再进入容器安装go相关所需要的环境

docker exec -itd 容器名 执行命令[sh]
# OPTIONS说明:
-d :分离模式: 在后台运行
-i :即使没有附加也保持STDIN 打开
-t :分配一个伪终端

我在命令后使用sh,代表在终端中进行交互,sh是docker绝大数容器都是使用的交互命令。

[root@192 ~]# docker exec -it go sh
Error response from daemon: Container 5dc7cf5ac8478f36d0dfc9e6c68e84df306af8cfdb0e1a79be6b0978a3c80307 is not running

但是当我们用docker exec 进入go容器的时候出现,go容器没有在运行,为什么?这是和docker的运行有关,docker对于启动的容器要求必须存在一个能够挂起运行的状态,否则程序启动即停止。

这很好理解因为对于docker来说它验证的容器是必须能够一直运行的,但是呢我们创建的容器因为没有挂起程序所以对docker来说相当于没有运行。

# 先删除go容器,然后重新docker run创建
docker rm go

# 在docker run的时候在命令的最后增加一个一定能挂起运行的命令,比如ping
docker run -p 8080:80 --name go -d alpine:3.18 ping www.baidu.com

# 再docker ps 查看即可发现存在
docker ps 

这个时候我们继续使用docker exec -it go sh命令进入到go容器中,完成go环境的搭建。

进入容器安装go

在进入到容器中安装go的时候,我们需要注意一点,即就是将安装过程所用到的命令和操作记录起来,因为在dockerfile中也会用到这些命令来构建容器。

mkdir /go
cd /go
wget --no-check-certificate https://golang.google.cn/dl/go1.21.0.linux-amd64.tar.gz
tar -C /usr/local -zxf go1.21.0.linux-amd64.tar.gz

# 此处我们需要删除已经解压后的go包,因为对于docker来说下载下来的文件也会影响到它的大小
# 因我们期望docker是足够的小,顾对于一些无用的软件文件是建议删除卸载
rm -rf /go/go1.21.0.linux-amd64.tar.gz 

# 注意!这一步是因为alpine系统对go程序运行的时候默认查找的类库与提供的类库不一致
# 故需要做此操作。
mkdir /lib64
ln -s /lib/libc.musl-x86_64.so.1 /lib64/ld-linux-x86-64.so.2

# 配置go的系统环境
export GOPATH=/go
export PATH=/usr/local/go/bin:$GOPATH/bin:$PATH

# 验证
go version
go version go1.21.0 linux/amd64

基于dockerfile构建go容器镜像

在上面的过程中,我们是先构建好一个初始化的alpine系统,然后进入到alpine系统中逐步安装go,但在应用开发中上面的构建过程大都是相同的,如何提升效率呢?

这个时候我们就可以通过dockerfile帮助我们提高构建的效率,它的工作方式就是将我们要在容器中执行的命令操作,事先写在dockerfile中,docker可以识别dockerfile中的内容,然后把它们翻译成容器会执行的命令,然后准备执行命令并最终构建好一个镜像,我们再根据镜像启动容器。
图片描述

这样做的好处就是,用户只需要调整dockerfile文件中的命令,即可构建不同的容器,大大提供了构建容器的效率,同时因为是文件的关系其他人也可以通过dockerfile了解到系统是如何搭建程序的。

# 我们需要引入到基础容器
FROM alpine:3.18

# 注意看这里我们的写法, 在sh中 && 可以表示下一条命令连续执行,而 \ 则是命令的分隔符号
# 思考:为什么这么写?
RUN mkdir /go && cd /go \
    && wget --no-check-certificate https://golang.google.cn/dl/go1.21.0.linux-amd64.tar.gz \
    && tar -C /usr/local -zxf go1.21.0.linux-amd64.tar.gz \
    && rm -rf /go/go1.21.0.linux-amd64.tar.gz \
    && mkdir /lib64 \
    && ln -s /lib/libc.musl-x86_64.so.1 /lib64/ld-linux-x86-64.so.2 
   
# 配置系统环境变量
# 在dockerfile中对容器的系统环境变量配置统一采用ENV这个关键词定义
ENV GOPATH /go
ENV PATH /usr/local/go/bin:$GOPATH/bin:$PATH

# 这个命令可以让我们的docker容器在启动的时候就执行下面的命令
# 把原本在docker run中的命令放到dockerfile中,并示意启动容器的时候执行
# 但是如果在docker run后跟新的命令会代替CMD中的命令
CMD ["ping", "www.baidu.com"]

补充注意,在dockerfile中的注释前不能有空格;然后通过如下命令构建docker容器。

# docker build 即根据dockerfile构建镜像,-t 是指构建容器的名称格式是 name:tag 或 name
# . 是指使用当前目录下的dockerfile构建,也可以通过 -f 参数指定
docker build -t go .

# 检查是否构建好
docker images

# 如果存在构建不好或者多余的镜像可以通过如下命令删除,-f 是强制删除
docker rmi 镜像名 

# 根据镜像构建容器
docker run --name go -d go

# 然后我们可以执行下面的命令测试
docker exec -it go go

通过容器运行go-zero

我预先调整了user/api中的代码,使得api暂时不关联其他程序。

import (
	"github.com/zeromicro/go-zero/rest"
	"demo/user/api/internal/config"
	"demo/user/api/internal/middleware"
	"demo/user/rpc/userclient"
)

type ServiceContext struct {
	Config            config.Config
	UserClient        userclient.User
	LoginVerification rest.Middleware
}

func NewServiceContext(c config.Config) *ServiceContext {
	return &ServiceContext{
		Config: c,
		//UserClient:        userclient.NewUser(zrpc.MustNewClient(c.UserRPC)),
		LoginVerification: middleware.NewLoginVerificationMiddleware().Handle,
	}
}

func (l *UserLogic) User(req *types.UserReq) (resp *types.UserResp, err error) {
	// todo: add your logic here and delete this line
	return &types.UserResp{
		Id:    "666",
		Name:  "木兮老师",
		Phone: "13011110000",
	}, nil
}

因为对当前的我们来说,先学习如何通过容器运行go-zero是关键,而增加复杂度反而效果不佳,所以先使得api服务不与其他服务关联,后面会讲如何关联访问。

我们将go-zero上传到服务中

//这是我上传的目录地址

/go/user

我们构建一个新的容器,用于启动并访问go-zero

docker run -p 8888:8888 -v /go/user:/go/src/demo/user --name go-zero -d go 

在上面的命令中通过-p绑定容器与宿主机的端口,而-v是绑定容器与宿主机共享的目录,也就是这个目录下的内容会影响到双方,称之为数据卷。

然后进入容器

# 先执行如下命令
go env -w GOPROXY=https://goproxy.io
# 然后下载依赖
go mod tidy
# 运行
cd api/
go run .

然后测试即可

基于打包部署

除了上面的方式外我们还可以基于编译程序运行,这种会相对简单,即将go-zero预先编译打包,然后通过dockerfile提前复制到容器中并启动的时候执行。这种方式我们可以应用在服务发布测试或者生产的时候。

o'o# CGO_ENABLED=0 
GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -o bin/user-api ./api/user.go

然后我们新建一个新的dockerfile,在新的dockerfile中我们可以选择继续基于go这个镜像构建也可以基于alpine镜像构建,但目前我们采取的方式是使用编译后go-zero项目的二进制文件部署因此可以直接用alpine镜像最佳,因为不需要go的环境

FROM alpine:3.18

# 这个关键词的意思是复制的意思,可以将宿主机中的内容复制到容器中
# 命令 左边是宿主机的目录,右边是容器目录
RUN mkdir /user && mkdir /user/bin && mkdir /user/conf

# 复制编译后的二进制文件
COPY bin/user-api /user/bin/
# 复制配置文件
COPY api/etc/user.yaml /user/conf/

# 为二进制提供执行权限
RUN chmod +x /user/bin/user-api

# 该命令指定容器会默认进入那个目录,如我们每次进入服务器的时候会自动进入root目录一样的作用
WORKDIR /user

# 这个命令可以让我们的docker容器在启动的时候就执行下面的命令
# 与CMD不同之处是,在docker run 后跟的命令不能替换它,它仍然会启动的时候执行
ENTRYPOINT ["bin/user-api", "-f","/user/conf/user.yaml"]

构建容器

docker build -t user-api .
docker run -p 8888:8888 --name go-zero -d user-api

小结

本节主要讲解dockerfile的使用,在dockerfile使用过程中大家可能会遇到一些问题

问题1:dockerfile构建过程中出现问题如何解决

解:这个问题在构建的时候可以先构建好dockerfile中使用的基础镜像,然后再把dockerfile中使用的命令放到容器中逐条执行验证

问题2:概念误解,如我构建一个go的容器,有的同学可能会误以为这是go的系统

docker-compose编排

容器网络

我们先了解容器的网络,在后续的使用中,我们会涉及到容器的网络应用,它是docker体系知识中一个重要的知识点。

docker在安装后运行的时候会默认创建三个网络,我们可以通过docker network ls查看所有的网络。

[root@192 ~]# docker network ls
NETWORK ID     NAME      DRIVER    SCOPE
252a2ca6302a   bridge    bridge    local
65a576c82770   host      host      local
e0a7aac94266   none      null      local

none模式

在这种模式下容器会独立network,但并没有对其进行任何的网络设置,如分配ip等。

bridge模式

在该模式中,Docker 会创建一个虚拟以太网桥 docker0,新建的容器会自动桥接到这个接口,然后docker会依据docker0在创建的时候设立的网络段给容器分配ip。

图片描述
但默认的方式存在一个问题,就是每次重启docker默认的网络段也会发生变化,而采用该网络段的docker容器也会跟着发生变化。当然我们也可以自定义一个网络段,然后自己给创建的容器分配指定的ip。

# 命令格式
docker network create --subnet=<subnet> <network_name>
docker network create --subnet=172.0.0.0/24 net-test

# 查看网络段详情
docker network inspect net-test

# 删除网络段
docker network rm net-test

# 给容器分配网络段
docker run --name go-net-test --ip 172.0.0.2 --net net-test -d go

# 结果
[root@192 ~]# docker exec -it go-net-test ipaddr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
43: eth0@if44: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue state UP 
    link/ether 02:42:ac:00:00:02 brd ff:ff:ff:ff:ff:ff
    inet 172.0.0.2/24 brd 172.0.0.255 scope global eth0
       valid_lft forever preferred_lft forever
[root@192 ~]# 

host模式

  • host 网络模式需要在创建容器时通过参数 --net host 或者 --network host 指定;
  • 采用 host 网络模式的 Docker Container,可以直接使用宿主机的 IP 地址与外界进行通信,若宿主机的 eth0 是一个公有 IP,那么容器也拥有这个公有 IP。同时容器内服务的端口也可以使用宿主机的端口,无需额外进行 NAT 转换;
  • host 网络模式可以让容器共享宿主机网络栈,这样的好处是外部主机与容器直接通信,但是容器的网络缺少隔离性。

图片描述

docker容器互通

再看看docker容器的互通,即在docker中内部之间又如何互通呢?在容器中的连接通讯方式我们可以采用三种方式

  1. 通过宿主机做桥接
  2. 容器都在同一网络段
  3. 通过link命令

1.通过宿主机做桥接

这种方式的话就是在构建容器的时候与宿主机绑定端口,对外暴露服务的方式。

docker run -p 80:80 -d go

容器内部之间的请求先走宿主机,然后再通过宿主机访问到容器,一般在跨服务的时候应用。

2.容器都在同一网络段

通过自定义网络段,然后让创建的容器都处于在这个网络段中,容器之间就可以通过分配好的网络ip相互之间即可访问。如下哎例子

docker run --name go-net-test3 --ip 172.0.0.3 --net net-test -d go

[root@192 ~]# docker exec -it go-net-test sh
/ # ping 172.0.0.3
PING 172.0.0.3 (172.0.0.3): 56 data bytes
64 bytes from 172.0.0.3: seq=0 ttl=64 time=0.202 ms
64 bytes from 172.0.0.3: seq=1 ttl=64 time=0.123 ms

这种方式可以应用在不同的服务类型中。

3.通过link命令

我们可以在构建容器的时候添加一个–link的指令,使得容器在构建出来后,就可以与指定的容器进行绑定。两个容器之间可以通过容器名相互访问,但是这种方式仍然需要在同一个网络段下,默认使用的是docker0这个网络段。

docker run --name go-net4 --link go-net-test --net net-test -d go

[root@192 ~]# docker exec -it go-net-test sh
/ # ping go-net4
PING go-net4 (172.0.0.4): 56 data bytes
64 bytes from 172.0.0.4: seq=0 ttl=64 time=0.203 ms
64 bytes from 172.0.0.4: seq=1 ttl=64 time=0.213 ms

因此3需要基于2的基础上进行实现,在使用上3会有较好的优势,因为无需关注具体的网络ip,可以之间通过容器名进行访问。

部署api/rpc服务通讯

接着上次的内容将rpc服务通过docker部署并实现连调,在代码层面注意修改api服务在核心代码层对rpc客户端的初始化

type ServiceContext struct {
	Config            config.Config
	UserClient        userclient.User
	LoginVerification rest.Middleware
}

func NewServiceContext(c config.Config) *ServiceContext {
	return &ServiceContext{
		Config:            c,
		UserClient:        userclient.NewUser(zrpc.MustNewClient(c.UserRPC)),
		LoginVerification: middleware.NewLoginVerificationMiddleware().Handle,
	}
}

然后调整一下rpc中的数据来源,暂时不来源redis和mysql这将作为练习尝试。在开始的时候注意还需要先pull一个etcd,作为服务发现注册机制。

# 先停止所有容器,并进行删除
docker ps -a -q | xargs docker stop | xargs docker rm

如下是关于etcd的dockerfile_etcd

FROM bitnami/etcd:3.4.15

ENV ETCD_ENABLE_V2 true
ENV ALLOW_NONE_AUTHENTICATION yes
ENV ETCD_ADVERTISE_CLIENT_URLS http://etcd:2379
ENV ETCD_LISTEN_CLIENT_URLS http://0.0.0.0:2379
ENV ETCD_NAME etcd

构建镜像

docker build -t etcd -f ./Dockerfile_etcd .

docker run -d -p 2379:2379 -p 2380:2380 --net user --ip 168.10.0.20 --name etcd etcd

构建过程

  1. 构建好user-rpc的dockerfile
  2. 定义好桥接网络段
  3. 部署服务并使用该网段
  4. 通过容器名访问服务

构建好user-rpc的dockerfile

使用二进制的方式

FROM alpine:3.18

# 这个关键词的意思是复制的意思,可以将宿主机中的内容复制到容器中
# 命令 左边是宿主机的目录,右边是容器目录
RUN mkdir /user && mkdir /user/bin && mkdir /user/conf

# 复制编译后的二进制文件
COPY bin/user-rpc /user/bin/
# 复制配置文件
COPY rpc/etc/user.yaml /user/conf/

# 为二进制提供执行权限
RUN chmod +x /user/bin/user-rpc

# 该命令指定容器会默认进入那个目录,如我们每次进入服务器的时候会自动进入root目录一样的作用
WORKDIR /user

# 这个命令可以让我们的docker容器在启动的时候就执行下面的命令
# 与CMD不同之处是,在docker run 后跟的命令不能替换它,它仍然会启动的时候执行
ENTRYPOINT ["bin/user-rpc", "-f","/user/conf/user.yaml"]

注意修改配置

Name: User
Host: 0.0.0.0
Port: 8888
UserRPC:
  Etcd:
    Hosts:
      - etcd:2379
    Key: user.rpc
Name: user.rpc
ListenOn: 0.0.0.0:8080
Etcd:
  Hosts:
  - etcd:2379
  Key: user.rpc
Mysql:
  DataSource: root:000000@tcp(127.0.0.1:3306)/im?charset=utf8mb4&parseTime=true&loc=Asia%2FShanghai
Cache:
  - Host: 127.0.0.1:6379
    Type: node
    Pass:

构建好user-rpc并重新构建user-api

GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -o bin/user-api ./api/user.go
GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -o bin/user-rpc ./rpc/user.go


docker build -t user-api -f ./Dockerfile .
docker build -t user-rpc -f ./Dockerfile_rpc .

定义好桥接网络段

docker network create --subnet=175.0.0.0/24 user

部署服务并使用该网段

docker run --name etcd -p 2379:2379 --net user --ip 168.10.0.100 -d etcd
docker run --name user-rpc -p 8080:8080 --net user --ip 168.10.0.70 --link etcd -d user-rpc
docker run --name user-api -p 8888:8888 --net user --ip 168.10.0.50 --link etcd -d user-api

# etcd查询所有的key
etcdctl get --prefix ""

docker ps

docker-compose

在前面的内容中我们基本上就已经实现了服务的部署,但是在过程中存在问题,即我们可以看到在构建api/rpc/etcd容器的时候实际上过程是比较繁琐的,并且又具有较多重复性的工作,这个时候我们的需求就是期望有一个工具可以很好的帮助我们管理容器,可以一键启动所有容器一键停止所有容器,快速配置各个容器的命令参数。

这个时候我们就可以用到docker编排工具docker-compose,它是一个用于定义和运行多容器 Docker 应用程序的工具。它允许您使用一个简单的 YAML 文件来配置应用程序的各个服务,并通过一条命令启动、停止和管理这些服务。

通过使用 Docker Compose,您可以轻松地构建和管理应用程序的多个服务,例如数据库、Web 服务、消息队列等。它利用了 Docker 强大的容器化技术,使得应用程序的部署和扩展变得更加简单和可靠。

安装

sudo curl -L "https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose

docker-compose

# 离线方式
# 从github上下载对应版本
mv docker-compose-linux-x86_64 /usr/local/bin/
cd /usr/local/bin/
//修改文件名
mv docker-compose-linux-x86_64 docker-compose

//授权
sudo chmod +x /usr/local/bin/docker-compose

//查看安装是否成功
docker-compose -v

配置docker-compose.yaml

mkdir -p /etcd/data
mkdir -p /etcd/logs

chmod -R 777 ./etcd/data
chmod -R 777 ./etcd/logs
version: "3"

services:
  # 服务名
  etcd:
    # 选择镜像:镜像的选择会先从本地找,如果没有会去仓库中拉取下来
    image: etcd
    # 可以选择指定的dockerfile自动帮我构建
    build:
      # 指定dockerfile所在的目录
      context: ./ 
      # 指定dockerfile的文件名
      dockerfile: dockerfile_etcd
    # 定义创建的容器名
    container_name: etcd
    # 使创建的容器与宿主机绑定端口
    ports:
      - "2379:2379"
      - "2380:2380"
    # 配置系统环境变量  
    environment:
      - ETCD_ENABLE_V2=true
      - ALLOW_NONE_AUTHENTICATION=yes
      - ETCD_ADVERTISE_CLIENT_URLS=http://etcd:2379
      - ETCD_LISTEN_CLIENT_URLS=http://0.0.0.0:2379
      - ETCD_NAME=etcd
    # 配置容器与宿主机的共享目录  
    # 同时需要注意宿主机存在目录,并且要基于权限不然系统会直接报错
    volumes:
      - ./etcd/data:/bitnami/etcd/data
      - ./etcd/logs:/bitnami/etcd/logs
    # 设置容器的网络段  
    networks:
      guser:
   
  user-rpc:
    image: user-rpc
    container_name: user-rpc
    ports:
      - "8080:8080"
    # 与etcd服务互通  
    links:
      - etcd
    # 需要等指定容器启动后才可以启动,填写的是容器的服务名
    depends_on:  
      - etcd
    networks:
      guser:
      
  user-api:
    image: user-api
    container_name: user-api
    ports:
      - "8888:8888"
    # 与etcd服务互通  
    links:
      - etcd
    # 需要等指定容器启动后才可以启动,填写的是容器的服务名
    depends_on:  
      - etcd
      - user-rpc
    networks:
      guser:      
# 由docker创建      
networks:
  guser:
    driver: bridge

总结

在本节中主要讲解docker的网络以及docker-compose,通过docker部署好user的rpc与api服务,

在内本节中大家可能会遇到的问题有

容器之间无法实现互通

这个问题是很多初学者学习docker的时候经常会遇到的问题,解决思路。

  1. 首先梳理自己的镜像构建过程,容器的启动命令及过程,看看是否存在配置上 的问题
  2. 然后再看自己在配置和构建的时候api、rpc的配置信息是否有误
  3. 在调试中,你可以先部署一个服务,然后进入容器中通过利用ping检查是否可以访问到目标容器,然后用curl检测是否可以访问到容器中的程序【注意两个命令的不同哟】
  4. 问题往往会出现在如下情况
    1. 配置不正确
    2. 网络段不一致
    3. 容器中的服务没有启动
    4. 如果设置过自己宿主机的防火墙则需要重启docker

关于docker中的共享目录

在构建docker容器的时候,我们不能把它当做一个普通的程序看待,而是作为一个随时可运行可删除的程序来看待,当docker停止删除随之也会删除docker容器这个过程中在容器内部产生的数据,因此在程序中使用docker的时候,我们需要思考容器的数据是否需要保留以及重要性,如mysql、redis在用docker的时候就需要配置好数据卷共享目录,以免docker容器的停止运行造成数据的丢失问题。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1839777.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

嵌入式linux系统中SPI子系统验证03

今天主要给大家分享一下&#xff0c;如何使用SPI总线进行验证的方法。 第一&#xff1a;SPI验证流程 1. echo 1 > /dev / spidev3.0 2&#xff0e;逻辑分析仪抓波形 3.十六进指转化为十进制 4.ASCII字符代码表匹配 第二&#xff1a;SPI验证结果 第三&#xff1a;设备…

蚓链数字化生态平台,开启企业未来新篇章!

在如今数字化浪潮势不可挡的时代&#xff0c;企业发展可谓是机遇与挑战并存&#xff01;而蚓链数字化生态平台系统的出现&#xff0c;绝非是给企业一套平平无奇的营销方案或工具那么简单。 它赋予企业的&#xff0c;是在产业生态链中获取海量数据价值的关键且强大的能力&#x…

18个机器学习核心算法模型总结

最强总结&#xff01;18个机器学习核心算法模型&#xff01;&#xff01; 大家好~ 在学习机器学习之后&#xff0c;你认为最重要的算法模型有哪些&#xff1f; 今儿的内容涉及到~ 线性回归逻辑回归决策树支持向量机朴素贝叶斯K近邻算法聚类算法神经网络集成方法降维算法主成…

Weevil-Optimizer象鼻虫优化算法的matlab仿真实现

目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.本算法原理 5.完整程序 1.程序功能描述 Weevil-Optimizer象鼻虫优化算法的matlab仿真实现&#xff0c;仿真输出算法的优化收敛曲线&#xff0c;对比不同的适应度函数。 2.测试软件版本以及运行结果展示…

【Redis】基于Redission实现分布式锁(代码实现)

目录 基于Redission实现分布式锁解决商品秒杀超卖的场景&#xff1a; 1.引入依赖&#xff1a; 2.加上redis的配置&#xff1a; 3.添加配置类&#xff1a; 4.编写代码实现&#xff1a; 5.模拟服务器分布式集群的情况&#xff1a; 1.右键点击Copy Configuration 2.点击Modi…

虚拟现实环境下的远程教育和智能评估系统(十)

VR部署测试&#xff0c;采集眼动数据&#xff1b; 经VR内置Camera采集眼睛注视位置后&#xff0c;输出.txt形式的眼动结果&#xff1a; 经处理后&#xff0c;将射线方向和位置投影到视频屏幕二维坐标的位置&#xff1a; 在视频中可视化如下&#xff1a;

Redis的缓存击穿与解决

缓存击穿问题也叫热点Key问题&#xff0c;就是一个被高并发访问并且缓存重建业务较复杂的Key突然失效了&#xff0c;无数的请求访问会在瞬间给数据库带来巨大的冲击。 Redis实战篇 | Kyles Blog (cyborg2077.github.io) 目录 解决方案 互斥锁 实现 逻辑过期 实现 解决方案…

C++ 类与对象的使用要点(超详细解析,小白必看系列)

1.面向过程和面向对象初步认识 C语言是面向过程的语言&#xff0c;关注的是过程&#xff0c;分析出求解问题的步骤&#xff0c;通过函数调用逐步解决问题 例如&#xff1a;洗衣服 C是基于对象的&#xff0c;关注的是对象&#xff0c;将一件事拆分成不同的对象&#xff0c;靠对…

Hadoop3:MapReduce中的Partition原理及自定义Partition

一、默认Partition分区配置 以WC案例来进行验证。 1、设置setNumReduceTasks 修改的代码 这行代码&#xff0c;确定了reduceTask的数量&#xff0c;也确定了分区逻辑 在mapper文件中&#xff0c;打上断点 计算分区的代码 这里会对每一个kv进行计算&#xff0c;然后&#…

STM32F4 STD标准库串口接收中断+空闲中断例程

STM32F4 STD标准库串口接收中断空闲中断例程 &#x1f516;工程基于STM32F446 ✨用惯了STM32CubeMX傻瓜式配置&#xff0c;突然改用标准库写代码&#xff0c;初始化外设内容&#xff0c;总是丢三落四的。 &#x1f4d7;串口初始化配置 void uart_init(uint32_t bound) {//GPIO…

基于51单片机FM数字收音机设计

基于51单片机FM数字收音机 &#xff08;程序&#xff0b;原理图&#xff0b;PCB&#xff0b;设计报告&#xff09; 功能介绍 具体功能&#xff1a; 该系统利主要由STC89C51单片机、液晶显示器、按键、调频收音模块TEA5767、功放LM386组成。 1.收音芯片采用TEA5767模块&…

最新PHP仿猪八戒任务威客网整站源码/在线接任务网站源码

资源介绍 老规矩&#xff0c;截图为亲测&#xff0c;前后台显示正常&#xff0c;细节功能未测&#xff0c;有兴趣的自己下载。 PHP仿猪八戒整站源码下载&#xff0c;phpmysql环境。威客开源建站系统&#xff0c;其主要交易对象是以用户为主的技能、经验、时间和智慧型商品。经…

阿里云域名解析

阿里云域名控制台&#xff1a;https://dc.console.aliyun.com/next/index#/domain-list/all

Mobvista汇量科技解析奥运机会点及营销理念,看广告投放如何抢占先机

四年一度的奥运盛会&#xff0c;作为少有能跨越文化、宗教、种族、行为等各方面差异的体育事件&#xff0c;更能广泛吸引全球观众的目光&#xff0c;成为品牌方和广告主天然的流量磁铁。应用增长平台Mobvista汇量科技为助力各行业开发者、各品牌商家抢占奥运流量&#xff0c;分…

搜维尔科技邀您共赴2024第四届轨道车辆工业设计国际研讨会

会议内容 聚焦“创新、设计、突破”&#xff0c;围绕“面向生命健康、可持续发展的轨道交通系统” 为主题&#xff0c;从数字化、智能化、人性化、绿色发展等方面&#xff0c;探索轨道交通行业的设计新趋势及发展新机遇。 举办时间 2024年7月10日-12日 举办地点 星光岛-青岛融…

串扰(二)

三、感性串扰 首先看下串扰模型及电流方向&#xff1a; 由于电感是阻碍电流变化&#xff0c;受害线的电流方向和攻击线的电流方向相反。同时由于受害线阻抗均匀&#xff0c;故有Vb-Vf&#xff08;感应电流属于电池内部电流&#xff09;。 分析感性串扰大小仍然是按微分的方法…

三个“消失” 折射债市新变化

资金分层现象逐步消失&#xff1b;低位的DR007利率已不常见&#xff1b;债市中一度盛行的“滚隔夜”也在逐渐减少。 当前&#xff0c;债券市场正在出现一系列显著变化&#xff1a;资金分层现象逐步消失&#xff1b;低位的DR007利率已不常见&#xff1b;债市中一度盛行的“滚隔…

坚持刷题|反转链表

文章目录 题目思考实现1. 迭代方式实现链表翻转2. 递归方式实现链表翻转 Hello&#xff0c;大家好&#xff0c;我是阿月。坚持刷题&#xff0c;老年痴呆追不上我&#xff0c;今天继续链表&#xff1a;反转链表 题目 LCR 024. 反转链表 思考 翻转链表是一个常见的算法问题&a…

杂说咋说-关于城市化发展和城市治理的几点建议(浙江借鉴)

杂说咋说-关于城市化发展和城市治理的几点建议&#xff08;浙江借鉴&#xff09; 近年来&#xff0c;浙江省坚持一张蓝图绘到底&#xff0c;推动城市化发展和城市治理不断迈上新台阶&#xff0c;全省城市化水平和城市治理能力牢牢居于全国第一方阵。当前&#xff0c;国内外环境…

男内裤哪个品牌质量好?口碑最好的男士内裤品牌

男士内裤&#xff0c;作为男士日常穿着的必需品&#xff0c;选择一款合适的内裤对于男士的健康和舒适度至关重要。然而&#xff0c;市面上男士内裤品牌众多&#xff0c;款式各异&#xff0c;让人眼花缭乱。那么&#xff0c;买男士内裤选择哪一款好呢&#xff1f;下面&#xff0…