微服务必备容器化技术

文章目录

  • 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 fastyum 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 --nowdocker 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.ConfigUserClient        userclient.UserLoginVerification 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 linereturn &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 1000link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00inet 127.0.0.1/8 scope host lovalid_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:ffinet 172.0.0.2/24 brd 172.0.0.255 scope global eth0valid_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.ConfigUserClient        userclient.UserLoginVerification 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.15ENV 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:2379Key: user.rpc
Name: user.rpc
ListenOn: 0.0.0.0:8080
Etcd:Hosts:- etcd:2379Key: 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:6379Type: nodePass:

构建好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.godocker 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-composedocker-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/logschmod -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-rpccontainer_name: user-rpcports:- "8080:8080"# 与etcd服务互通  links:- etcd# 需要等指定容器启动后才可以启动,填写的是容器的服务名depends_on:  - etcdnetworks:guser:user-api:image: user-apicontainer_name: user-apiports:- "8888:8888"# 与etcd服务互通  links:- etcd# 需要等指定容器启动后才可以启动,填写的是容器的服务名depends_on:  - etcd- user-rpcnetworks: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.mzph.cn/bicheng/30203.shtml

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

相关文章

最新技术:跨境电商源码,应对多国市场需求,让您轻松开展全球业务!

随着全球化进程的不断推进&#xff0c;跨境电商已成为企业拓展国际市场的重要途径。为了满足不同国家和地区消费者不断增长的需求&#xff0c;跨境电商源码应运而生&#xff0c;为企业提供了便捷高效的全球化业务发展方案。 一、全球化运营的关键 跨境电商源码的核心功能在于…

基本循环神经网络(RNN)

RNN背景&#xff1a;RNN与FNN 在前馈神经网络中&#xff0c;信息的传递是单向的&#xff0c;这种限制虽然使得网络变得更容易学习&#xff0c;但在一定程度上也减弱了神经网络模型的能力。 在生物神经网络中&#xff0c;神经元之间的连接关系要复杂的多。前馈神经网络可以看着…

PySide(PyQt)的特殊按钮(互锁、自锁、独占模式)

界面图: Qt Designer中创建窗口,放置一个QGroupBox,命名为btnStation,这就是自定义的按钮站,按钮站里放置6个按钮。自锁按钮相当于电器中的自锁功能的按钮,每按一次状态反转并保持不变。独占按钮也是自锁功能的按钮,不同的是当独占按钮为ON时,其余所有按钮均被置为OFF…

SmartEDA革新电路设计:告别繁琐,轻松步入智能时代!

在数字化浪潮席卷而来的今天&#xff0c;电路设计的复杂性和繁琐性一直是工程师们面临的难题。然而&#xff0c;随着科技的进步&#xff0c;一款名为SmartEDA的电路设计工具应运而生&#xff0c;它以智能化、高效化的特点&#xff0c;彻底颠覆了传统电路设计的方式&#xff0c;…

在3dmax软件中如何快速创建毛发?---模大狮模型网

在3D建模和渲染中&#xff0c;为角色或物体添加逼真的毛发效果是提升场景真实感的重要步骤之一。然而&#xff0c;手动一根一根创建毛发是非常繁琐的&#xff0c;因此掌握如何在软件中快速生成和调整毛发效果至关重要。模大狮将详细介绍如何利用3ds Max 2018创建毛发&#xff0…

Salia PLCC cPH2 远程命令执行漏洞(CVE-2023-46359)

漏洞描述 Salia PLCC cPH2 v1.87.0 及更早版本中存在一个操作系统命令注入漏洞&#xff0c;该漏洞可能允许未经身份验证的远程攻击者通过传递给连接检查功能的特制参数在系统上执行任意命令。 产品界面 fofa语法 "Salia PLCC" POC GET /connectioncheck.php?ip1…

发论文idea来了!强化学习+Transformer,29个创新点汇总

基于Transformer的强化学习&#xff08;TRL&#xff09;是一种利用Transformer模型架构来改进和增强强化学习算法性能的方法。 这种方法通过结合Transformer模型强大的表示能力和强化学习的决策优化框架&#xff0c;显著提升了智能体的学习能力和适应能力&#xff0c;为我们解…

dockerfile文件的中的命令

# 基础镜像 FROM registry.cn-beijing.aliyuncs.com/205erp/myopenjdk:8.6 # 设置工作目录 WORKDIR /opt # 拷贝jar包到工作目录 COPY target/*.jar app.jar RUN ls # 设置暴漏的端口 EXPOSE 8080 # 启动jar包 CMD java ${JAVA_TOOL_OPTIONS} -jar app.jar

N7745A Keysight 是德 多端口光功率计 简述

N7745A光功率计专为表征多端口光器件而设计&#xff0c;适用于多路复用器、PON分路器、波长选择开关&#xff08;WSS&#xff09;和ROADM等多端口器件的测试。它可以节省通道空间&#xff0c;通过LAN或USB连接进行并行编程&#xff0c;集成多种设备到单一设置&#xff0c;提高了…

企业设备管理现状与解决方案

在当今企业运营中&#xff0c;设备管理作为保障生产稳定、提升效率的重要环节&#xff0c;其复杂性和挑战性日益凸显。无论是生产车间、石油化工、物业小区&#xff0c;还是消防器材、建筑施工等领域&#xff0c;都面临着设备故障频发、维修流程繁琐等共性问题。 为了帮助企业…

VUE3实现个人网站模板源码

文章目录 1.设计来源1.1 网站首页页面1.2 个人工具页面1.3 个人日志页面1.4 个人相册页面1.5 给我留言页面 2.效果和源码2.1 动态效果2.2 目录结构 源码下载万套模板&#xff0c;程序开发&#xff0c;在线开发&#xff0c;在线沟通 作者&#xff1a;xcLeigh 文章地址&#xff1…

对比4090及4090D:国区“特供”与原版相比有何区别?

2023年12月28日 英伟达宣布正式发布GeForce RTX 4090D&#xff0c;对比于一年前上市的4090芯片&#xff0c;两者的区别与差异在哪&#xff1f;而在当前比较火热的大模型推理、AI绘画场景方面 两者各自的表现又如何呢&#xff1f; 规格与参数信息对比现在先来看看GeForce RT…

SCI绘图【1】-不同颜色表示密度和差异--密度图

参考资料&#xff1a;密度图&#xff08;Density Plot&#xff09; - 数据可视化图表 - 数字孪生百科 密度图是快速观察变量数值分布的有效方法之一。通常情况下&#xff0c;会根据两个变量将平面绘图区域分为非常多的子区域&#xff0c;之后以不同颜色表示落在该区域上样本的…

揭秘!家用空气净化器针对“毛絮、灰尘”的制胜秘诀是什么?

亲爱的朋友们&#xff01;作为一个家庭主妇&#xff0c;我想和大家聊聊我日常生活中那些让人头疼的飞尘和毛絮问题。 每天忙得团团转&#xff0c;累得腰酸背痛&#xff0c;但家里仍然飘着那些烦人的飞尘和毛絮。它们就像一群顽皮的小精灵&#xff0c;四处飞舞&#xff0c;怎么…

《2024攻防演练必修高危漏洞集合》

1 漏洞汇总数据 以下数据针对自2024年3月以来截止到目前在攻防演练过程红队利用率比较高的漏洞进行总结汇总&#xff0c;具体的数据如下所示&#xff1a; ●远程代码执行漏洞 漏洞数量&#xff1a;6个 涉及厂商&#xff1a;YzmCMS、畅捷通、pgAdmin、泛微、锐捷、奇安信、 ●…

如何通过自己编写Jmeter函数

在Jmeter的函数助手里&#xff0c;有很多内置的函数&#xff0c;比如Random、UUID、time等等。使用这些函数可以快速帮我们生成某些数据&#xff0c;进行一些逻辑处理。用起来非常的方便。 但是在实际接口测试过程中&#xff0c;有很多的需求&#xff0c;Jmeter内置的函数可能…

苹果不会等到明年才对 Siri 进行改进|TodayAI

据彭博社报道&#xff0c;今年苹果&#xff08;APPLE&#xff09;将推出一个更令人满意的 Siri。 当 iOS 18 今年秋季推出时&#xff0c;Siri 的功能不仅仅是让你的 iPhone 边缘显示彩虹光环。虽然苹果智能功能要到 2025 年才会向非测试版用户推出&#xff0c;但据报道&#x…

每天写java到期末考试(6.19)--1.百元买百鸡

好久没有写了&#xff0c;现在赶快先复习复习&#xff0c;哈哈&#xff0c;加油&#xff01; 收获&#xff1a;写了好久&#xff0c;才写好这一个问题&#xff0c;提示自己不要好高骛远&#xff0c;前期先踏踏实实写好每一个代码&#xff1b; 被困住原因 取余%与整除/区别 pa…

Linux 图形化编程GTK3.0 快速入门之布局

GTK3.0 布局之水平布局 核心语法&#xff1a; 水平布局容器&#xff1a; 水平布局容器的创建&#xff1a; GtkWidget *gtk_hbox_new( gboolean homogeneous, gint spacing ); homogeneous&#xff1a;容器内控件是否大小一致( gboolean 取值为TRUE 或 FALSE ) spacing&#…

Qemu 模拟 Mini2440 扩展SDRAM 64M 到 128M,256M(三)

1. Mini2440 最大支持的SDRAM 是128M+128M MINI2440 板子的内存是由两片64M大小的SDRAM组成,所以实际内存有128M。分别连接到芯片的BANK6和BANK7。从这个图可以看出 Mini2440 最大支持的SDRAM 是128M+128M,我们能不能利用 QEMU 直接给你模拟干满到 256M呢?各位看官看我的操作…