暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

Fastapi框架-(16)docker-compose容器编排一键搭建和启动本地环境

小儿来一壶枸杞酒泡茶 2021-08-18
827

番外篇:

从前面几个实践的示例看,我们的自己构建的py3的镜像其实是超级大的。一不小心就把C盘给吃的差不多了!所以接下来首先就是考虑,能不能使用最小的镜像来作为我们的运行的容器呐?这个不管怎么样还是得去做,毕竟后续如果你上线生产环境的话,也是需要考虑这个镜像优化的问题。

1 docker镜像空间情况

1.1镜像占用情况查询:

mayn@DESKTOP-16CKEN1 MINGW64 d/code/python/local_python/docker_fastapi
$ docker system df
TYPE TOTAL ACTIVE SIZE RECLAIMABLE
Images 2 0 106.6MB 106.6MB (100%)
Containers 0 0 0B 0B
Local Volumes 8 0 151.9MB 151.9MB (100%)
Build Cache 63 0 3.476GB 3.476GB
复制代码

1.2镜像空间占用清理

mayn@DESKTOP-16CKEN1 MINGW64 d/code/python/local_python/docker_fastapi
$ docker system prune
WARNING! This will remove:
- all stopped containers
- all networks not used by at least one container
- all dangling images
- all dangling build cache

Are you sure you want to continue? [y/N] y
复制代码

  • docker container prune
     命令是删除停止的容器

  • docker system prune
     命令清楚

清理前:

清理后:

不过奇怪C盘的占用还是没减少!

再查看镜像docker 占用的空间

mayn@DESKTOP-16CKEN1 MINGW64 d/code/python/local_python/docker_fastapi
$ docker system df
TYPE TOTAL ACTIVE SIZE RECLAIMABLE
Images 2 0 106.6MB 106.6MB (100%)
Containers 0 0 0B 0B
Local Volumes 0 0 0B 0B
Build Cache 0 0 0B 0B
复制代码

有点奇葩吧!哈哈,万能的重启大法之后,!!!! 

阔以了哈!

2 docker不同的基础镜像的构建的区别

对比不同基础镜像构建的文件大小,有些小的镜像有些库安装异常对比:

FROM python:3.8
WORKDIR app
COPY requirements.txt .
RUN pip install --upgrade pip -i http://pypi.douban.com/simple/ --trusted-host pypi.douban.com \
&& pip install setuptools==33.1.1 -i http://pypi.douban.com/simple/ --trusted-host pypi.douban.com \
&& pip install -i https://mirrors.aliyun.com/pypi/simple/ --trusted-host pypi.douban.com -r requirements.txt
复制代码

FROM python:3.7-alpine
WORKDIR app
COPY requirements.txt .
RUN pip install --upgrade pip -i http://pypi.douban.com/simple/ --trusted-host pypi.douban.com \
&& pip install setuptools==33.1.1 -i http://pypi.douban.com/simple/ --trusted-host pypi.douban.com \
&& pip install -i https://mirrors.aliyun.com/pypi/simple/ --trusted-host pypi.douban.com -r requirements.txt
复制代码

构建出来两个镜像进行对比:

验证测试发现FROM python:3.7-alpine的也能运行,只是部分的安装包,再

-r requirements.txt
复制代码

是无法安装的!!!!

尝试进入到容器里面进行安装!!然后再打包新的镜像!!!!

这种方式也不行!!它找遍了所有的版本也是找不到!安装不了!!应该是阉割了什么地方导致安装不了!!

更换为:

FROM python:3.7
WORKDIR app
COPY requirements.txt .
RUN pip install --upgrade pip -i http://pypi.douban.com/simple/ --trusted-host pypi.douban.com \
&& pip install setuptools==33.1.1 -i http://pypi.douban.com/simple/ --trusted-host pypi.douban.com \
&& pip install -i https://mirrors.aliyun.com/pypi/simple/ --trusted-host pypi.douban.com -r requirements.txt
复制代码

这种方式是可以安装的,说明,某些基础的镜像虽然是小,但是不会兼容一些其他库的安装!

最终不同的镜像的构建结果:

正传:

1 编排前传-分别启动容器

如前面讲到示例:

version: "3.3"
services:
fastapi_web_01:
image: fastapi_web:latest
build: .
container_name: fastapi_web_api_01
restart: always
ports:
- "1245:8080"
fastapi_web_02:
image: fastapi_web:latest
build: .
container_name: fastapi_web_api_02
restart: always
ports:
- "1246:8080"

复制代码

上面通过一个文件就可以同时启动两个的API服务!

之前有提到过,我们的本机服务部署通常会涉及到多个容器之间的相互的通信,比如的吗api服务需要依赖的有:

  • redis 缓存服务

  • postgeresql 数据库服务

  • rabbitmq 消息中间件服务等等

如果避免手动的管理启动多个关联之间的容器呐?那就是我们的docker-compose进行容器编排的关键原因!使用一个docker-compose的文件就可以同时的串联所有的容器,并且容器之间的是相互通信的!

关于容器间的通信,我这么暂时不展开!后续看看有时间单独重新梳理一下docker一些基础只是使用!

假设我们的一个项目启动,需要的容器对象如下:

  • api 服务-fatsapi构建的

  • redis 服务,用于api服务中进行缓存的处理

  • postgresql 服务用户api服务的数据存贮

  • nginx 的服务,用户负载分发动多个API服务后端

那上面看启动这个项目基本上我们的就需要三个容器对象才可以支撑起来。那我首先肯定需要把这几个容器的依赖的镜像都给拉下来咯!是吧!一个一个的手动去启动和管理!多累人!

1.1 拉一个redis的镜像

PS D:\code\python\local_python\docker_fastapi> docker pull redis:4.0.1
复制代码

1.2 拉一个postgresql的镜像

PS D:\code\python\local_python\docker_fastapi> docker pull postgres:9.4
复制代码

1.3 拉一个nginx的镜像

PS D:\code\python\local_python\docker_fastapi> docker pull nginx
复制代码

编写自己API服务,用于构建我们的API服务(纯演示示例,代码就不那么讲究拉):

1.4 测试验证链接redis的容器:

1.4.1:先启动一个redis容器对象

1.4.2 代码链接容器

编写链接代码,注意点(服务是运行再我们上面自定容器里面滴有!也就我们的docker搭建的本地的环境):

```
#!/usr/bin/evn python
# -*- coding: utf-8 -*-
"""
-------------------------------------------------
文件名称 : main
文件功能描述 : 功能描述
创建人 : 小钟同学
-------------------------------------------------
-------------------------------------------------
"""
from fastapi import FastAPI
from aioredis import create_redis_pool, Redis

import uvicorn
app = FastAPI()

async def get_redis_pool() -> Redis:
# 注意这个也是需要容器内才可以!---
redis = await create_redis_pool(f"redis://127.0.0.1:5566/0?encoding=utf-8")
# redis = await create_redis_pool('redis://localhost:9699')
await redis.set('my-key', 'value')
value = await redis.get('my-key', encoding='utf-8')
print(value)
return redis


@app.on_event('startup')
async def startup_event():
"""
获取链接
:return:
"""
app.state.redis = await get_redis_pool()


@app.on_event('shutdown')
async def shutdown_event():
"""
关闭
:return:
"""
app.state.redis.close()
await app.state.redis.wait_closed()


@app.get("/")
def read_root():

# 测试连接redis

# 测试连接数据库

return {"小钟同学": "sadsd"}

if __name__ == '__main__':
# 启动服务
uvicorn.run('main:app', host='0.0.0.0', port=8081, debug=True, reload=True, access_log=False,workers=1, use_colors=True)
```
复制代码

此时我们的链接会提示有异常:

正如我们前面说的。API服务是运行于一个容器,redis是运行于另一个容器,涉及到容器互联了!这个时候,就需要对我们的连接做一定的改变!!!!

首先就是我们的想到的就是:--link,使用它,再我们的api服务的启动的时候,去链接我们的刚刚的

容器。

1.4.3 容器互联

修改后我们的启动的api服务的命令是:

--entrypoint -v D:/code/python/local_python/docker_fastapi:/opt/project --link fastapi-redis:redis -p 127.0.0.1:8081:8081 --rm
复制代码

修改代码的链接容器redis的方式:

1.5 测试验证链接postgresql的容器:

1.5.1:先启动一个postgresql容器对象

错误,无法启动我们pg容器,查看启动日志信息:

需要设置其他启动的信息,设置相关用户名等和数据库等,该用命令模式启动:

docker run --name fastapi_pg -v D:/data/fastapi_pg/pgdata:/var/lib/postgresql/data -e POSTGRES_PASSWORD=123456 -p 9999:5432 -d postgres:9.4
复制代码

容器能正常的启动了: 

挂载文件也正常了:

使用客户端连接测试验证:

1.5.2:配置API服务启动的是去链接我们的pg容器

1.5.3:编写连接容器内的数据库代码测试验证

#!/usr/bin/evn python
# -*- coding: utf-8 -*-
"""
-------------------------------------------------
文件名称 : main
文件功能描述 : 功能描述
创建人 : 小钟同学
创建时间 : 2021/8/2
-------------------------------------------------
修改描述-2021/8/2:
-------------------------------------------------
"""
from fastapi import FastAPI
from aioredis import create_redis_pool, Redis

import uvicorn
app = FastAPI()


async def get_redis_pool() -> Redis:
# 注意这个也是需要容器内才可以!---
redis = await create_redis_pool(f"redis://redis/0?encoding=utf-8")
# redis = await create_redis_pool('redis://localhost:9699')
await redis.set('my-key', '测试设置')
value = await redis.get('my-key', encoding='utf-8')
print('设置获取',value)
return redis


@app.on_event('startup')
async def startup_event():
"""
获取链接
:return:
"""
app.state.redis = await get_redis_pool()

import psycopg2
# 获得游标对象
conn = psycopg2.connect(database="ceshi", user="postgres", password="123456", host="mypgdb", port="5432")
cursor = conn.cursor()
# sql语句
sql = "SELECT VERSION()"
# 执行语句
cursor.execute(sql)
# 获取单条数据.
data = cursor.fetchone()
# 打印
print("database version : %s " % data)
# 事物提交
conn.commit()
# 关闭数据库连接
conn.close()


@app.on_event('shutdown')
async def shutdown_event():
"""
关闭
:return:
"""
app.state.redis.close()
await app.state.redis.wait_closed()


@app.get("/")
def read_root():

# 测试连接redis

# 测试连接数据库

return {"小钟同学": "sadsd"}

if __name__ == '__main__':
# 启动服务
uvicorn.run('main:app', host='0.0.0.0', port=8081, debug=True, reload=True, access_log=False,workers=1, use_colors=True)
复制代码

这里的代码注意点是:

查看输出结果,已能连接容器PG的对象:

1.6 测试通过nginx容器访问API容器

先配置我们的本地nginx挂载目录等信息,用于nginx配置文件同步

1.6.1 创建挂载目录

mayn@DESKTOP-16CKEN1 MINGW64 ~
$ mkdir -p D:/data/nginx/{conf,conf.d,html,logs}
复制代码

1.6.2 创建配置文件信息

d:/data/nginx/conf/nginx.conf

user  nginx;
worker_processes 1;

error_log var/log/nginx/error.log warn;
pid var/run/nginx.pid;


events {
worker_connections 1024;
}


http {
include etc/nginx/mime.types;
default_type application/octet-stream;

log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';

access_log var/log/nginx/access.log main;

sendfile on;
#tcp_nopush on;

keepalive_timeout 65;

#gzip on;

include etc/nginx/conf.d/*.conf;
}
复制代码

1.6.3 创建配置代理API配置文件

D:/data/nginx/conf.d/fastapi.conf

upstream dcokerfatapiapi {

server naughty_poincare weight=1 max_fails=0 fail_timeout=12s; # PS:这服务naughty_poincare 名称不需要再加端口号了,容器已自动映射别名进行关联和端口的绑定了
}

server {
listen 80;
server_name localhost; # 这是HOST机器的外部域名,用地址也行

location {
proxy_pass http://dcokerfatapiapi; # 这里是指向 gunicorn host 的服务地址
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
复制代码

1.6.4 启动nginx容器

docker run --name fatyapi_nginx -d -p 8888:80 -v D:/data/nginx/html:/usr/share/nginx/html -v D:/data/nginx/conf/nginx.conf:/etc/nginx/nginx.conf  -v D:/data/nginx/logs:/var/log/nginx -v D:/data/nginx/conf.d:/etc/nginx/conf.d -d nginx:latest
复制代码

查看启动失败!

查看日志分析:

修改配置文件信息,再进行重启容器:

查看容器的元数据信息:

访问我们的地址进行验证:

http://127.0.0.1:8888/

出现502,说明无法代理访问到我们的API服务:

分析我们的代理配置文件里面按理应该是写我们的API容器名称1!

但是写上了 反而不对了!!有点奇怪!!!想起来好像没进行链接!nginx需要链接到我们的API容器上!所以其的nginx容器的时候需要做链接!!!先实验出,再修改启动命令!重新启动的nginx容器!

docker run --name fatyapi_nginx -d -p 8888:80 --link tender_albattani:fatapinginx -v D:/data/nginx/html:/usr/share/nginx/html -v D:/data/nginx/conf/nginx.conf:/etc/nginx/nginx.conf  -v D:/data/nginx/logs:/var/log/nginx -v D:/data/nginx/conf.d:/etc/nginx/conf.d -d nginx:latest
复制代码

详细说明: 

奇怪了!还是502!!!!

进入nginx容器内部进行访问也是502:

1.6.5 排错nginx代理API服务异常问题

简单另一个nginx测试验证一下:

mayn@DESKTOP-16CKEN1 MINGW64 ~
$ docker run -d --name ncxxnginx -p 8887:80 nginx
d71aed67d91480d2a72a0ca93d341ee2d38bc0908c338e2c6746737bebecb898
复制代码

然后外网访问:http://127.0.0.1:8887/

有点奇怪!!!这时候再查看一下我们的nginx错误日志一下!!!因为我们的做了外部文件的挂载直接的看一下外部的日志文件信息:

所以这种情况下,我们的可以考虑到是因为我们的文件问题了!!

再次访问我们的:http://127.0.0.1:8888

此时终于成功通过我们的nginx 容器 代理访问我们的测试环境下的API容器服务了!!!!!

1.7 总结

综上所述,终于把我们的几个服务通过容器的方式都串联起来了!!!!但是过程非常的复杂!!而且我们的测试环境API随时会重启!!每次api重启的或有可能我们的容器名称会变!!!!这样就不行了!!!!所以上面生产环境肯定是不会这样!!!就算是测试环境的话,可能也有点繁琐!!!!

下一步尝试使用一个文件来启动!!!

docker-compose 中的容器互联

1:认识--link的本质

如之前我们的APP启动的一个容器实例的时候示例是:

--entrypoint -v D:/code/python/local_python/docker_fastapi:/opt/project --link fastapi-redis:redis --link fastapi_pg:mypgdb -p 127.0.0.1:8081:8081 --rm
复制代码

之前在部署调试的环境的时候,容器之间的互联的调试是使用--link来进行容器直接的互联,--link的本质其实是在容器内进行host修改。

如此时我们我们的进入到上次的App容器实例对象内查看容器hots信息如下:

# C:\Users\mayn>docker exec -it 19f bin/sh
# cat etc/hosts
复制代码

通过上面的查看我们的相关容器的情况,甚至我们的相互ping:

# ping 172.17.0.2
PING 172.17.0.2 (172.17.0.2) 56(84) bytes of data.
64 bytes from 172.17.0.2: icmp_seq=1 ttl=64 time=0.035 ms
64 bytes from 172.17.0.2: icmp_seq=2 ttl=64 time=0.031 ms
复制代码

PS:不过这--link的模式再相关的版本中是已标注了即将过期了,也就是不再推荐使用这种方式进行容器之间的互联了!

2:认识--docker网络

Docker是基于Linux的Namespaces技术来进行资源隔离如,所以可以进行资源隔离有很多,如:

  • PID Namespace隔离进程

  • Mount Namespace隔离文件系统

  • Network Namespace隔离网络

而Network Namespace隔离网络是主要解决容器相关网络访问问题,一个Network Namespace隔离网络会虚拟出独立的一个网卡、路由、iptable规则等,每个Network Namespace之间都相互独立的。

默认启动一个容器(使用的是桥接模式的网络)默认会分配独立的Network Namespace,host网络模式则不会!

docker再安装成功后,默认的会宿主机会虚拟分配有一个docker0的网卡,这个docker0网卡同时也是所有容器默认的网关。Docker每次动任何一个的容器的时候,都会根据我们的docker往前的网段分配给的容器的一个ip地址。

通常我们的默认的启动一个容器的时候,容器默认的使用的网络的模式其实桥接的bridge模式。这种模式的情况,通常的网络是需要先经过宿主主机的网卡,然后再到我们的docker0的网卡然后进行NAT的转换再到达对应的容器的内部的相关服务进程。docker实际是在iptables做了NAT规则,来实现端口转发功能。实现容器访问的访问。

查看当前我们的docker的所有的网络模式:

$ docker network ls
NETWORK ID NAME DRIVER SCOPE
2a5fe145cdb2 bridge bridge local
34db8b01fe88 host host local
66f6b7b72659 none null local
复制代码

上诉的默认的几个网络是无法进行删除,如果需要删除自定义网络可以使用:

docker network rm NETWORK ID(容器ID)
复制代码

Docker可以有以下4种网络模式:

  • host模式:使用 --net=host 指定。

  • none模式:使用 --net=none 指定。

  • bridge模式:使用 --net=bridge 指定,默认设置 或 不写--net参数,就是bridge模式。

  • container模式:使用 --net=container:NAME_or_ID 指定。

2.1 host模式

配置命令:

- net= host
复制代码

说明:

  • 容器和宿主机共享Network namespace。

这种网络模式的下的容器网络接口的是和宿主机共用,它的网络不和宿主机的网络隔离(当然只是网络不进行隔离,其他如文件系统进程还有其他啥是隔离滴)。此时容器中监听的相关的端口的应用可以直接被宿主机进行访问,此时就不需要像之前我们的学到的需要做所谓的端口映射才能访问容器内部的服务进程。

host模式网络的缺点就是:

  • 容器占用的端口启动其他容器的时候就无法继续的使用

  • host网络没有与宿主机网络隔离,有可能会引发安全隐患或端口冲突

2.2 Bridge模式

处于同一个宿主机上的所有Bridge模式下的容器之间的容器通信可以通过IP的方式进行相互的访问。

默认情况下,当我们的启动一个新的容器实例对象的时候,我们的docker会从docker0子网中分配一个IP给容器使用,并设置docker0的IP地址为容器的默认网关。

因为默认的所有的同一宿主机器启动的所欲的容器都是处于同一个网桥下的,我们可以通过查看具体的容器内部的网络元信息可以查看的到:

  • 查看容器网络

$ docker inspect ad8
复制代码

  • 查看docker所有的桥接网络元信息:

mayn@DESKTOP-16CKEN1 MINGW64 ~
$ docker network inspect bridge
复制代码

通过上面的命令可以看得出:我们当前所有的使用默认网络模式下的所有的容器实例。

补充说明,之前我们再制作对应的镜像的文件Dockerfile的时候,通过是基于桥接模式下,所以如果内部的服务需要对外可以进行访问的话是需要进行端口暴露,此时,需要通过Dockerfile中的EXPOSE
一起使用把容器内的需要访问的端口对外暴露,然后通过映射的方式进行访问。

如果我们的不暴露对应的端口的话,容器内的服务肯定是无法进行访问滴!

而如果我们的是基于使用HOST模式的话,则不需要进行端口的暴露也是可以访问容器内的服务,因为容器器启动的时候就是直接的使用了宿主机的相关的端口。和宿主机是共享的方式。此时使用容器内默认的端口,也可以进行容器内部的服务的访问!

2.3 none模式

这种模式下的容器内部是没有任何的网络可供外部进行调用的,此时容器内部是没有任何:网络配置和IP的信息,也没有路由等信息,有的仅仅只是自己lo 回环网络(lo代表127.0.0.1,即localhost)
如有需要的,我们需要自己进行配置添加处理。

2.4 container模式

这种模式主要是指定当前新创建的容器和已存一个容器共享同一个网络,而不是和宿主机进行共享,当前新创建的容器不会创建自己内部的网卡和配置自己的ip,而是直接使用了已存在的容器的共享IP和端口.(这模式和HOTS的基本相似,除了网络进行共享之外,其他都是处于隔离状态)。

此模式下的容器之间的通信主要是通过lo 网卡设备通信
.

3:集群服务下的 docker networks

3.1 自定义网桥简单示例

除了我们的上面--link的这种方式进行容器间的互联之外,最优的就是自定义docker networks。如下示例演示,首先创建两个py3容器示例,用于验证:

默认启动所有的容器都是使用桥接模式的验证:

  1. 启动三个py3的容器:

  1. 查看当前我们的网桥模式下元数据信息

查看网络列表:

$ docker network ls
NETWORK ID NAME DRIVER SCOPE
c9e2031700be bridge bridge local
34db8b01fe88 host host local
66f6b7b72659 none null local
复制代码

查看c9e2031700be bridge的元数据:

$ docker network inspect c9e
这个下面被bridge进行桥接的容器实例有:
"Containers": {
"4d7acdcc955c25d310b9c85d61c96e552a0b5e1a89b121c27ec5e5a863ce577e": {
"Name": "ceshi3",
"EndpointID": "0a494f721baecf2ea97d536725583313fb4b5122b1a57a77e199599451fdcf69",
"MacAddress": "02:42:ac:11:00:03",
"IPv4Address": "172.17.0.3/16",
"IPv6Address": ""
},
"688225e3e02fc69c525dcce19b6126addd90f8a893cde749cc0cfd660ea7a1a6": {
"Name": "ceshi2",
"EndpointID": "091d160ea8153263730cf9aa53074808eb969ed377a2dc60fbc45ab7d541892a",
"MacAddress": "02:42:ac:11:00:02",
"IPv4Address": "172.17.0.2/16",
"IPv6Address": ""
},
"78f0a94354c507962d3856ea6360eb4d250c1b98f6abfeaff045ba944e46d245": {
"Name": "amazing_mendeleev",
"EndpointID": "07a363a9973bc9b886d237fa024288daad4ca05c90b24db2c76b0b0562a2b1c5",
"MacAddress": "02:42:ac:11:00:04",
"IPv4Address": "172.17.0.4/16",
"IPv6Address": ""
}
},
复制代码

  1. Bridge网桥双向通讯下的自定义网桥

  • 创建一个网桥

docker network create -d bridge py3ceshibridge
复制代码

创建之后,查看网络列表:

$ docker network ls
NETWORK ID NAME DRIVER SCOPE
c9e2031700be bridge bridge local
34db8b01fe88 host host local
66f6b7b72659 none null local
93dbaca0589e py3ceshibridge bridge local
复制代码

将ceshi2容器和ceshi3容器使用新创建出来的网桥连接

$ docker network connect py3ceshibridge ceshi2
$ docker network connect py3ceshibridge ceshi3
复制代码

查看自定义网桥的网络信

$ docker network inspect 93d
复制代码

自定义的网桥下的信息有:

"Containers": {
"4d7acdcc955c25d310b9c85d61c96e552a0b5e1a89b121c27ec5e5a863ce577e": {
"Name": "ceshi3",
"EndpointID": "c4293f47595cc5e361d1723d6c95d6f731c5970eccb553606922289104e3d5ce",
"MacAddress": "02:42:ac:12:00:03",
"IPv4Address": "172.18.0.3/16",
"IPv6Address": ""
},
"688225e3e02fc69c525dcce19b6126addd90f8a893cde749cc0cfd660ea7a1a6": {
"Name": "ceshi2",
"EndpointID": "6df7d329a970e2a4a1b5ab79eb0b27244912f3dc52146863674caab0c49a425c",
"MacAddress": "02:42:ac:12:00:02",
"IPv4Address": "172.18.0.2/16",
"IPv6Address": ""
}
},
复制代码

3.2 集群服务下默认自定义网桥

通常我们的再进行集群服务的部署时候,一般是直接的使用docker-compose.yml文档快速编排、部署应用服务。

通常默认的情况networks启动的作用的就是默认的进行把两个处于同一个docker-compose.yml相关的容器进行串联起来,把所有的容器都添加同一个自定义的网桥网络中(个人理解)。当然如果在docker-compose.yml中如果没有指定的networdks的话,则默认通过:docker-compose up
启动的关联的容器都会默认被加入项目名_default
网络中。

示例如:

配置文件信息:

version: '3'
services:
redis:
image: "redis:alpine"

mypgdb:
image: "postgres:9.4"
restart: always
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: 123456
POSTGRES_DB: ceshi
ports:
- '5432:5432'
复制代码

查看启动相关容器: 

再次查看网络列表信息:

总结:当我们的使用docker-compose up一键编排容器后,(没有指定网络名称的情况下)里面相关的容器都会默认会添加到目录名_default
网络中。此时docker-compose up启动的容器之间,可以通过应用名找到彼此:

如上面redis容器可以直接通过:mypgdb这名称来找到我们的数据库容器的IP,同理数据库容器也可以通过redis这个名称:来找到redis容器所属的IP。

PS: 启动容器之间想端口是通过容器内部的CONTAINER_PORT端口进行通信,不是外部映射的端口。

3.3 集群服务下指定已存在的网桥

通过上面的示例可以知道,默认的情况下,docker-compose up一键编排启动的容器都是使用默认项目名称下的网桥的名称,那如果需要自己指定和定义的话就需要自己写入到yml文件里面。

如下示例:

先创建一个已存在网络:

$ docker network create -d bridge zyx-existing-network
复制代码

修改配置文件,进行知道连接到指定的网络:

version: '3'

networks:
default:
external:
# 指定链接到这个已存在网络上
name: zyx-existing-network

services:
redis:
image: "redis:alpine"

mypgdb:
image: "postgres:9.4"
restart: always
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: 123456
POSTGRES_DB: ceshi
ports:
- '5432:5432'
复制代码

再次的启动docker-compose up后再查看具体的网络的元数据信息:

暂停我们的所有容器:

再启动查看元数据信息,就没有看到了!

上面铺叙那么多,其实主要是为了下面理解docker-compose一些参数的展开而已,当然这里记录也没那么详细,后续有机会再单独的进行专题的记录一下!

4 docker-compose一键搭建和启动本地环境(py3+redis+postgres)

4.1 定义容器编排内容

version: '3.4'
# 创建网络
networks:
# 指定网络名称
zyx-txnet:
# 知道网络模式是桥接的模式
driver: bridge

services:
fastapi:
container_name: fastapi-evn
build: .
image: py3:latest
# 指定使用网络
networks:
- zyx-txnet
restart: always
ports:
- 0.0.0.0:8081:8081
# 依赖mypgdb 和 redis的容器的启动
depends_on:
- mypgdb
- redis

redis:
container_name: redis
image: redis:latest
# 指定使用网络
networks:
- zyx-txnet
volumes:
- D:/data/fastapi_zyx_redis/redis/conf:/etc/redis/
- D:/data/fastapi_zyx_redis/redis/data:/data
- D:/data/fastapi_zyx_redis/redis/log/:/usr/local/redis/log/
ports:
- 6379:6379

mypgdb:
image: "postgres:9.4"
# 指定使用网络
networks:
- zyx-txnet
restart: always
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: 123456
POSTGRES_DB: ceshi
volumes:
- D:/data/fastapi_zyx_pg/pgdata:/var/lib/postgresql/data
ports:
- 5432:5432
复制代码

其中需要注意的事项点有:

  • 确定好容器之间的依赖关系,确定容器的启动顺序

  • 是否需要指定特点的网络

  • 主要环境变量的定义确保发相关服务的启动

4.2 使用pycharm链接docker-compose

等待编译完成:

4.3 启动我们的测试代码

#!/usr/bin/evn python
# -*- coding: utf-8 -*-
"""
-------------------------------------------------
文件名称 : main
文件功能描述 : 功能描述
创建人 : 小钟同学
创建时间 : 2021/8/2
-------------------------------------------------
修改描述-2021/8/2:
-------------------------------------------------
"""
from fastapi import FastAPI
from aioredis import create_redis_pool, Redis

import uvicorn
app = FastAPI()


async def get_redis_pool() -> Redis:
# 注意这个也是需要容器内才可以!---
redis = await create_redis_pool(f"redis://redis/0?encoding=utf-8")
# redis = await create_redis_pool('redis://localhost:9699')
await redis.set('my-key', '测试设置')
value = await redis.get('my-key', encoding='utf-8')
print('设置获取',value)
return redis


@app.on_event('startup')
async def startup_event():
"""
获取链接
:return:
"""
app.state.redis = await get_redis_pool()

import psycopg2
# 获得游标对象
conn = psycopg2.connect(database="ceshi", user="postgres", password="123456", host="mypgdb", port="5432")
cursor = conn.cursor()
# sql语句
sql = "SELECT VERSION()"
# 执行语句
cursor.execute(sql)
# 获取单条数据.
data = cursor.fetchone()
# 打印
print("database version : %s " % data)
# 事物提交
conn.commit()
# 关闭数据库连接
conn.close()


@app.on_event('shutdown')
async def shutdown_event():
"""
关闭
:return:
"""
app.state.redis.close()
await app.state.redis.wait_closed()


@app.get("/")
def read_root():

# 测试连接redis

# 测试连接数据库

return {"小钟同学": "少时诵诗书所所所所所所所所所所所"}

if __name__ == '__main__':
# 启动服务
uvicorn.run('main:app', host='0.0.0.0', port=8081, debug=True, reload=True, access_log=False,workers=1, use_colors=True)
复制代码

启动:

查看我们的相关网络信息:

以上仅仅是个人结合自己的实际需求,做学习的实践笔记!如有笔误!欢迎批评指正!感谢各位大佬!

结尾

END

简书:www.jianshu.com/u/d6960089b…

掘金:juejin.cn/user/296393…

公众号:微信搜【小儿来一壶枸杞酒泡茶】

小钟同学 | 文 【原创】【欢迎一起学习交流】| QQ:308711822

文章转载自小儿来一壶枸杞酒泡茶,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论