Fastapi框架+KubeSphere3.1.1系列(6):手动的部署fastapi-redis+postgresql服务+滚动升级(使用阿里云镜像仓库)

1,959 阅读20分钟

一、说明

1.1 部署概述

前期我们的已经大致的了解了如何去部署一个简单的py项目了,那如何组合整个部署呐?其中涉及的到的问题,也无非是之前我提到几个问题点。

  • 镜像的准备
  • 镜像环境配置
  • 镜像仓库的准备
  • 服务存储卷的准备

大概的也就以上的几点。那如何的进行一组应用的服务的部署串联起来呐?这是我这个小节需要思考的?

本小节大概涉及主要知识点有:

  • fastapi的环境的变量的读取(因为后续我们的一下数据库秘钥和其他是通过环境变量的方式进行配置的)
  • kubesphere上的配置信息和我们的fastapi的环境的变量对应起来(因为我们的程序是读取环境变量的)

1.2 部署的流程步骤

本小节部署的流程步骤大概分为以下的几个:

  • 第一步:各个服务镜像准备
  • 第二步:把镜像推送到阿里云镜像仓库(主要是考虑网络问题,为了拉取快一点)
  • 第三步:使用KubeSphere从阿里云镜像仓库拉取对应的镜像组成应用的服务组件
  • 第四步:使用NoddPort的方式开启对外集群访问

二、第一步:各个服务镜像准备

2.1 应用服务的组成

应用的组成主要是由以下的几个组件来组成的(暂时不搞消息队列进来):

  • fastapi服务镜像
  • redis镜像
  • postgresql镜像

大致的项目结构如下:

image.png

2.2 早期简单fastapi服务的编写

首先这里我这个服务呐,我不会写的太负责,后面我们的用我自己的脚手架的时候再进行展开叙述,我们这里使用最简单的方式,就是我们之前的写的一个示例:

#!/usr/bin/evn python
# -*- coding: utf-8 -*-
"""
-------------------------------------------------
   文件名称 :     main
   文件功能描述 :   功能描述
   创建人 :       小钟同学
   创建时间 :          2021/8/2
-------------------------------------------------
   修改描述-2021/8/2:         
-------------------------------------------------
"""
from fastapi import FastAPI
import uvicorn
# 这里的aioredis2.0版本的变化很大
import aioredis
# 定义应用实例
app = FastAPI()

# 获取
async def get_redis_pool() :
    # 注意这个也是需要容器内才可以!---
    # redis = await aioredis.create_redis(address, password=password)
    # 会自动的复用链接,也就是自动的启用连接池
    redis = aioredis.from_url("redis://localhost", encoding="utf-8", decode_responses=True)
    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
    await  app.state.redis.set('my-key', '测试设置')
    value = await app.state.redis.get('my-key', encoding='utf-8')
    # 测试连接数据库
    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()

    return {"小钟同学读取数据库示例": "redis读取到的信息:{};数据库读取到的内容:{}".format(value,data)  }

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)

但是这里我们需要修改一下,因为后续我们部署到K8S的时候,很多的参数都是写到环境变量里面,服务通过环境变量的方式来读取。 所以这里需要改造一下我们的上面的示例,引入环境变量的读取机制。

2.3 改写fastapi服务,引入环境变量读取

关于环境变量的读取,其实fastapi中的实现的话,有好几种方式,以下是我自己所了解到的几种方式:

  • os包下的 os.getenv()方法
  • Pydantic中的BaseSettings自动绑定解析
  • python-dotenv库解析读取.env文件中设置
  • dynaconf 库读取环境变量

下面我简单的展开一下,也当做自己备忘的记录!

环境变量的几个测试参数准备:

image.png

image.png

2.3.1 os包下的 os.getenv()方法示例

import os
POSTGRESQL_PASSWORD = os.getenv("POSTGRESQL_PASSWORD", "没有环境变量的情况下的默认值--》没有密码")
POSTGRESQL_HOST = os.getenv("POSTGRESQL_HOST", "没有环境变量的情况下的默认值--》默认值没有HOST")
print(POSTGRESQL_PASSWORD)
print(POSTGRESQL_HOST)

输出结果:

ceshi0001
host00001

2.3.2 Pydantic中的BaseSettings自动绑定解析


from pydantic import BaseSettings
class Settings(BaseSettings):
    POSTGRESQL_PASSWORD: str = "没有环境变量的情况下的默认值--》没有密码"
    POSTGRESQL_HOST: str = "没有环境变量的情况下的默认值--》默认值没有HOST"

settings = Settings()
print(settings.POSTGRESQL_PASSWORD)
print(settings.POSTGRESQL_HOST)

输出结果:

ceshi0001
host00001

2.3.2 python-dotenv库解析读取

这个主要是偏向于读取.evn,这里我就不加多解析。

from dotenv import load_dotenv, find_dotenv
from pathlib import Path  # Python 3.6+ only
# 一、自动搜索 .env 文件
load_dotenv(verbose=True)
# 二、与上面方式等价
load_dotenv(find_dotenv(), verbose=True)
# 三、或者指定 .env 文件位置
env_path = Path('.') / '.env'
load_dotenv(dotenv_path=env_path, verbose=True)

····另一个库的话比较新把,感兴趣可以自己去了解体验一下!

2.3.3 改写fastapi服务当前示例情况:

fastapi框架本身就自带了 Pydantic的属性,所以我下面的就使用它改造一下:

#!/usr/bin/evn python
# -*- coding: utf-8 -*-
"""
-------------------------------------------------
   文件名称 :     main
   文件功能描述 :   功能描述
   创建人 :       小钟同学
   创建时间 :          2021/8/2
-------------------------------------------------
   修改描述-2021/8/2:         
-------------------------------------------------
"""
from fastapi import FastAPI
import uvicorn
# 这里的aioredis2.0版本的变化很大
import aioredis
# 定义应用实例
app = FastAPI()


# =====
from pydantic import BaseSettings
class Settings(BaseSettings):
    # 后面是默认值,我这里是为了说明加上去的!!!!!!别介意!!!!!
    POSTGRESQL_PASSWORD: str = "没有环境变量的情况下的默认值--》没有密码"
    POSTGRESQL_HOST: str = "mypgdb"
    POSTGRESQL_DB: str = 'ceshi'
    POSTGRESQL_USER: str = 'postgres'

    # 默认其实是我们的创建K8S服务的名称
    REDIS_HOST = 'myredis'

settings = Settings()

print(settings.POSTGRESQL_PASSWORD)
print(settings.POSTGRESQL_HOST)
print(settings.POSTGRESQL_DB)

# 获取
async def get_redis_pool() :
    # 注意这个也是需要容器内才可以!---
    # redis = await aioredis.create_redis(address, password=password)
    # 会自动的复用链接,也就是自动的启用连接池
    redis =  aioredis.from_url("redis://{}".format(settings.REDIS_HOST), encoding="utf-8", decode_responses=True)
    return redis


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

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

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

    return {"小钟同学读取数据库示例": "首页访问测试!"}
    # return {"小钟同学读取数据库示例": "redis读取到的信息:{};数据库读取到的内容:{}".format(value,data)  }



@app.get("/redis")
async def read_root():
    await  app.state.redis.set('my-key', 'redis测试设置')
    value = await app.state.redis.get('my-key', encoding='utf-8')
    return {"小钟同学读取redis:": "value %s"%(value)}


@app.get("/postgresql")
async def read_root():
    import psycopg2
    # 获得游标对象
    conn = psycopg2.connect(database=settings.POSTGRESQL_DB, user="postgres", password=settings.POSTGRESQL_PASSWORD, host=settings.POSTGRESQL_HOST, port="5432")
    cursor = conn.cursor()
    # sql语句
    sql = "SELECT VERSION()"
    # 执行语句
    cursor.execute(sql)
    # 获取单条数据.
    data = cursor.fetchone()
    # 打印
    print("database version : %s " % data)
    # 事物提交
    conn.commit()
    # 关闭数据库连接
    conn.close()

    return {"小钟同学读取数据库示例redis": "database version : %s " % data}




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)

2.4 使用 docker-compose编排我们的服务(非必须-可忽略)

2.4.1 为什么使用 docker-compose编排我们的服务?

这里为啥要需要使用我们的docker-compose编排服务呐?不是说要上K8S的吗?其实我还没用到自动化流水线的功能,关于服务的镜像打包的话,还是需要手动的打包一下。所以这里的编排主要目的还是为了生成服务镜像,这样后续可以直接的提交到我们的镜像仓库,然后通过k8s从镜像仓库拉取!

2.4.2 三个镜像服务的准备

参考我们的以前的示例,这里的话,那就是需要编排三个镜像服务了:

2.4.2.1 关于镜像打包一些前置说明

首先我们的api服务的后期是直接的通过K8S启动的,所以这里需要再镜像里面写入相关容器启动的相关服务命令 如下的Dockerfile 文件内容 只是打了镜像,但是没有进行相关服务启动的命令的配置,所以如果是后续需要在K8S里面启动的话,还需要吃重新的处理一下,加入启动的命令:

FROM python:3.7
WORKDIR /app
COPY ./app ./app
COPY requirements.txt .
RUN pip install --upgrade pip -i https://mirrors.aliyun.com/pypi/simple/ --trusted-host mirrors.aliyun.com \
    && pip install setuptools==39.1.0 -i https://mirrors.aliyun.com/pypi/simple/ --trusted-host mirrors.aliyun.com \
    && pip install -i https://mirrors.aliyun.com/pypi/simple/ --trusted-host mirrors.aliyun.com -r requirements.txt

2.4.2.2 Dockerfile打包一些知识说明补充

-   FROM: FROM指令指定的一个基础镜像层

-   LABEL: Dockerfile中通过标签(LABLE)方式指定了当前镜像的维护者.每个标签其实是一个键值对(Key-Value),在一个镜像当中可以通过增加标签的方式来为镜像添加自定义元数据.

-   WORKDIR: 指明镜像的工作目录

-   COPY: 目录,复制 将应用相关文件从构建上下文复制到了当前镜像中,并且新建一个镜像层来存储.

-   ENV: 设置环境变量

-   RUN: 执行命令, RUN指令会在FROM指定的基础镜像之上,新建一个镜像层来存储run安装内容信息.

-   EXPOSE: 指明容器内需要开启的监听端口 后续K8S可以直接使用默认

-   CMD: 启动时运行的命令

2.4.2.3 fastapi-api镜像打包(修改)

首先是定制我们的fastapi-api接口镜像(加入了服务的启动命令):

  • 需要有requirements.txt的依赖文件
  • 需要有api服务的Dockerfile文件
  • 执行打包镜像命令:
    docker build -t fastapi_k8s .
    或者
    docker image build -t fastapi_k8s:latest .
    

开始定义我们的Dockerfile 文件内容

遗憾的是:多数的alpine 镜像多我们的-psycopg2不支持啊,所以下面的多阶段示例 可以参考!也可以切换到其他的-切换到其他基础镜像也存在兼容问题!这个头大!!!!

#####################
# 编译依赖的配置文件#
#####################
FROM python:3.7.4-alpine as builder
# 设置工作目录
WORKDIR /app
# 复制本地依赖
COPY ./requirements.txt requirements.txt

# 设置Python解释器不生成字节码pyc文件
ENV PYTHONDONTWRITEBYTECODE 1
# 规范标准日志输出流的换行处理- 禁用输出缓冲-stdout输出不缓存的设置方法
ENV PYTHONUNBUFFERED 1

# 编译安装依赖文件到/app/python_wheels
RUN apk add --update gcc musl-dev python3-dev libffi-dev openssl-dev build-base && pip install --upgrade pip && pip wheel --no-cache-dir --no-deps --wheel-dir /app/python_wheels -r requirements.txt

# 拉取python的基础镜像
FROM python:3.7.4-alpine
# 设置当前镜像的维护者
LABEL maintainer="308711822@qq.com"
# 设置工作目录
WORKDIR /app
# 复制本地依赖
COPY ./app ./app

# 生成的编译文件复制到容器对应的路径下面
COPY --from=builder /app/python_wheels /app/python_wheels
# 安装python wheels
RUN pip install --no-cache /app/python_wheels/*

# 指明监听的端口
EXPOSE 8080

# 运行的命令
CMD ["uvicorn", "--host", "0.0.0.0", "app.main:app"]

所以最终还是回到起点直接的使用:python:3.7 基础镜像

```
FROM python:3.7
WORKDIR /app
COPY ./app ./app
COPY requirements.txt .
RUN pip install --upgrade pip -i https://mirrors.aliyun.com/pypi/simple/ --trusted-host mirrors.aliyun.com \
    && pip install setuptools==39.1.0 -i https://mirrors.aliyun.com/pypi/simple/ --trusted-host mirrors.aliyun.com \
    && pip install -i https://mirrors.aliyun.com/pypi/simple/ --trusted-host mirrors.aliyun.com -r requirements.txt \
     && rm -rf /root/.cache/pip

CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000", "--reload"]
```

docker-compose 文件内容

version: '3.7'

services:
  api:
    build: .
    container_name: "container-fastapitest-k8s"
    command: uvicorn app.main:app --host 0.0.0.0 --port 8080 --reload
    restart: always
    ports:
      - "8980:8080"
    depends_on:
      - mypgdb
      - myredis

  mypgdb:
    image: postgres:12.0-alpine
    container_name: "container-mypgdb"
    volumes:
      - postgres_data:/var/lib/postgresql/data/
    environment:
      - POSTGRES_USER=postgres
      - POSTGRES_PASSWORD=123456
      - POSTGRES_DB=ceshi
    expose:
      - 5432

  myredis:
    # 指定镜像名称,也是服务的名称
    container_name: "container-myredis"
    image: redis:alpine
    # 指定使用网络
    networks:
    - zyx-txnet
    volumes:
    - ./redis/conf:/etc/redis/
    - ./redis/data:/data
    - ./redis/log/:/usr/local/redis/log/
    ports:
    - 6379:6379

volumes:
  postgres_data:

PS:docker-compose编排 其他容器的拉取

PS:其实这里也没必要使用这个来排版处理,主要是想验证一下而已!

这里你完全自己去拉取你需要镜像到本地就可以了!

2.4.3 上传到我们k8s节点上(安装有docker就可以)

image.png

也可以直接的再windows下直接生成,然后登入阿里云直接的推送!

image.png

PS:主要是为了使用docker-compose 来生成我们的和拉取镜像

docker-compose up

或者你直接的单独的生成和拉取你需要的镜像:

[root@localhost ~]# docker pull redis:alpine
[root@localhost ~]# docker pull postgres:12.0-alpine
生成fastapi的镜像:
[root@localhost docker_kubesphere_fastapi]# docker build -t fsfastapi_k8s .

2.5 直接打包fastapi服务镜像

2.5.1 准备镜像文件dockerfile内容:

ps:上面2.4中试过其他的镜像都由于对psycopg2库的支持有问题,所以这里就直接使用python:3.7 这个会导致我们的镜像比较大!

FROM python:3.7
WORKDIR /app
COPY ./app ./app
COPY requirements.txt .
RUN pip install --upgrade pip -i https://mirrors.aliyun.com/pypi/simple/ --trusted-host mirrors.aliyun.com \
    && pip install setuptools==39.1.0 -i https://mirrors.aliyun.com/pypi/simple/ --trusted-host mirrors.aliyun.com \
    && pip install -i https://mirrors.aliyun.com/pypi/simple/ --trusted-host mirrors.aliyun.com -r requirements.txt \
     && rm -rf /root/.cache/pip

CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000", "--reload"]

2.5.2 构建镜像的操作:

(docker_fastapi) D:\code\python\local_python\docker_kubesphere_fastapi>docker build -t fastapi_k8s:v1.1.4 .
[+] Building 45.9s (10/10) FINISHED
 => [internal] load build definition from Dockerfile                 
·····

2.5.3 本地测试验证服务访问:

(docker_fastapi) D:\code\python\local_python\docker_kubesphere_fastapi>docker run -p 8081:8000 fastapi_k8s:v1.1.4

2.5.4 服务访问:

image.png

我们的镜像准备好后,下一步就是把镜像推送到我们的阿里云仓库!

2.6 准备阿里云镜像仓库加速镜像拉取

2.6.1 阿里云账号准备和登入开通容器镜像服务

image.png

image.png

个人版差不多了!仅仅是用于演示! image.png

2.6.2 镜像服务登入密码设置

PS:这个密码很重要后续拉取镜像的时候,是必须用到的!

image.png

image.png

QQ瞄瞄(我的设置)

2.6.3 镜像仓库的创建

  • 命名空间的设置

image.png

image.png

image.png

  • 设置仓库名称

image.png

image.png

  • 设置代码源完成直接创建完成

image.png

2.6.4 阿里云仓库操作指南记录

## 1. 登录阿里云Docker Registry

```
$ docker login --username=xxxxxxxxxx registry.cn-shenzhen.aliyuncs.com
```

用于登录的用户名为阿里云账号全名,密码为开通服务时设置的密码。

您可以在访问凭证页面修改凭证密码。

## 2. 从Registry中拉取镜像

```
$ docker pull registry.cn-shenzhen.aliyuncs.com/zyx-xiaozhong/fastapi-app:[镜像版本号]
```

## 3. 将镜像推送到Registry

```
$ docker login --username=xxxxxxxxxx registry.cn-shenzhen.aliyuncs.com$ docker tag [ImageId] registry.cn-shenzhen.aliyuncs.com/zyx-xiaozhong/fastapi-app:[镜像版本号]

$ docker push registry.cn-shenzhen.aliyuncs.com/zyx-xiaozhong/fastapi-app:[镜像版本号]
```

请根据实际镜像信息替换示例中的[ImageId]和[镜像版本号]参数。

## 4. 选择合适的镜像仓库地址

从ECS推送镜像时,可以选择使用镜像仓库内网地址。推送速度将得到提升并且将不会损耗您的公网流量。

如果您使用的机器位于VPC网络,请使用 registry-vpc.cn-shenzhen.aliyuncs.com 作为Registry的域名登录。

## 5. 示例

使用"docker tag"命令重命名镜像,并将它通过专有网络地址推送至Registry。

```
$ docker imagesREPOSITORY                                                         TAG                 IMAGE ID            CREATED             VIRTUAL SIZEregistry.aliyuncs.com/acs/agent                                    0.7-dfb6816         37bb9c63c8b2        7 days ago          37.89 MB$ docker tag 37bb9c63c8b2 registry-vpc.cn-shenzhen.aliyuncs.com/acs/agent:0.7-dfb6816
```

使用 "docker push" 命令将该镜像推送至远程。

```
$ docker push registry-vpc.cn-shenzhen.aliyuncs.com/acs/agent:0.7-dfb6816
```

2.6.5 总结操作步骤:

  • 1:登入阿里云仓库,密码是开通镜像仓库时候的设置的密码(使用自己的账号哟)

    docker login --username=xxxxxxxxxx registry.cn-shenzhen.aliyuncs.com
    
  • 2:推送我们的镜像

    docker push registry.cn-shenzhen.aliyuncs.com/zyx-xiaozhong/fastapi-app:[镜像版本号]
      
    

    请根据实际镜像信息替换示例中的[ImageId]和[镜像版本号]参数。

  • 3:k8s设置我们的拉取经常命令

    $ docker pull registry.cn-shenzhen.aliyuncs.com/zyx-xiaozhong/fastapi-app:[镜像版本号]
    

2.6.6 开始推送我们fastapi镜像到我们的阿里云仓库

  • 使用命令登入docker
[root@localhost ~]#  docker login --username=阿里云账号 registry.cn-shenzhen.aliyuncs.com
Password: 开启服务的时候的设置的密码
WARNING! Your password will be stored unencrypted in /root/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store

Login Succeeded
[root@localhost ~]#

  • 推送我们的fastapi的镜像

前提需要先打包好生成我们的fastapi的镜像:

[root@localhost docker_kubesphere_fastapi]# docker build -t fsfastapi_k8s .

PS: 数据库的镜像和redis的镜像可以从其他地方拉取,我们自己的镜像有定制为加速就上传阿里云仓库而已!

然后再给我们的镜像打个属于阿里云的镜像标签,这样才可以推送到阿里云(和之前的私有仓库一样)

# 查查刚刚我们打的镜像
[root@localhost docker_kubesphere_fastapi]# docker images|grep fs
fsfastapi_k8s                                                           latest        88ceab3e3242   8 minutes ago   964MB
[root@localhost docker_kubesphere_fastapi]#

# 开始打一个标签

[root@localhost docker_kubesphere_fastapi]# docker tag 88ceab3e3242 registry.cn-shenzhen.aliyuncs.com/zyx-xiaozhong/fastapi-app:v1.0

# 查询出来我们刚打了阿里云标签的镜像

[root@localhost docker_kubesphere_fastapi]# docker images|grep fastapi
fsfastapi_k8s                                                           latest        88ceab3e3242   10 minutes ago   964MB
registry.cn-shenzhen.aliyuncs.com/zyx-xiaozhong/fastapi-app             v1.0          88ceab3e3242   10 minutes ago   964MB
[root@localhost docker_kubesphere_fastapi]#


# 开始推送:

[root@localhost docker_kubesphere_fastapi]# docker push registry.cn-shenzhen.aliyuncs.com/zyx-xiaozhong/fastapi-app:v1.0

PS:注意是的打的标签的格式: registry.cn-shenzhen.aliyuncs.com/zyx-xiaozhong/xxxxxx:v1.0

推送图示: image.png

还可以推送其他的标签如我们的拉取的redis:apine:

[root@localhost ~]# docker images |grep redis
redis                                                                   alpine        f6f2296798e9   3 weeks ago      32.3MB
[root@localhost ~]#

docker tag f6f2296798e9 registry.cn-shenzhen.aliyuncs.com/zyx-xiaozhong/redis:v1.0

2.6.7 查可能阿里云仓库推送结果

image.png

image.png

PS:建议是先公开那个镜像的拉取,私有的情况下,目前测试发现拉取不到,后续再补充说明这个地方!

2.7 配置kubesphere的阿里云镜像仓库信息

按官方文档要求说明:

要使用私有仓库中的镜像,您必须先为私有仓库创建密钥,以便在 KubeSphere 中集成该私有仓库。

步骤 1:进入密钥页面

首先回到我们的kubesphere,以 project-regular 用户登录 KubeSphere Web 控制台并进入项目,在左侧导航栏中选择配置中心下的密钥,然后点击创建

image.png

步骤 2:配置基本信息

设置密钥的名称(例如 aliyun-registry-secret),然后点击下一步

image.png

步骤 3:配置镜像仓库信息

类型设置为 kubernetes.io/dockerconfigjson(镜像仓库密钥) 。要在创建应用负载时使用私有仓库中的镜像,您需要配置以下字段:

  • 仓库地址:镜像仓库的地址,其中包含创建应用负载时需要使用的镜像。
  • 用户名:登录镜像仓库所需的用户名。
  • 密码:登录镜像仓库所需的密码。
  • 邮箱(可选):您的邮箱地址。

image.png

配置详细的秘钥信息:

image.png

image.png

  • 仓库地址:registry.cn-shenzhen.aliyuncs.com
  • 用户名:阿里云的账号。
  • 密码:阿里云的账号镜像仓库的密码不是登入密码。
  • 邮箱(可选):您的邮箱地址。

image.png

然后点击创建即可!

2.8 开始构建一个新的应用

2.8.1 fastapi服务构建(自制应用)

image.png

2.8.2 fastapi服务应用命名

给应用名称起名:fastapi-redis-postgresql-test

image.png

2.8.3 添加组件-设置fastapi服务为无服务状态

image.png

image.png

2.8.4 设置fastapi服务无服务名称

image.png

2.8.5 从阿里云获取fastapi服务镜像

image.png

2.8.6 搜索阿里云上搜fastapi服务镜像

PS:我使用HTTP一直不行,后来删除了使用https就可以了

搜索镜像是:zyx-xiaozhong/fastapi-k8s-app:v1.1.1

旧版搜索: image.png

新版搜索: image.png

2.8.7 配置fastapi服务镜像端口暴露和环境变量

因为我打镜像的时候。没有编写默认的暴露,所以没有默认选项出现。

image.png

所以这个地方我自己手动的暴露一下端口:

image.png

环境变量配置:

这里呐是很关键滴,我们后面还会新建其他组件如redis和postgresql的组件,而我们的fastapi服务内部需要的环境变量信息,我们可以从k8s里面的配置或或秘钥等地方获取,或者及写入的方式!所以这个地方很关键!!!!!

image.png

回顾之前我们的服务需要环境变量信息有哪些:

POSTGRESQL_PASSWORD: str = "没有环境变量的情况下的默认值--》没有密码"
POSTGRESQL_HOST: str = "mypgdb"
POSTGRESQL_DB: str = 'ceshi'
POSTGRESQL_USER: str = 'postgres'

# 默认其实是我们的创建K8S服务的名称
REDIS_HOST = 'myredis'

PS:对应我的配置上,这里相关一些数据库密码之类,理论肯定是使用秘钥的方式存贮的,我这里直接的明文先写入环境,后续其实是需要新建秘钥的方式,选择从秘钥获取的

最终配置结果:

image.png

2.8.8 挂载和高级默认暂时不操作

image.png

image.png

2.8.9 添加redis服务有状态服务组件

image.png

image.png

命名为:myredis

image.png

设置镜像:redis:alpine

image.png

其他暂时都默认,也不挂载数据卷!

image.png

2.8.10 添加postgresql服务有状态服务组件

命名为:mypgdb

image.png

设置镜像:postgres:12.0-alpine

image.png

配置环境变量:

image.png

输入环境变量信息:

POSTGRES_PASSWORD:123456

其他暂时都默认,也不挂载数据卷!

2.8.11 完成一个组合

最终完成一个组合后直接创建:

image.png

image.png

查看构建情况:

image.png

等待服务创建部署完成:

image.png

2.8.12 给我们的fastapi开启外网访问

image.png

image.png

2.8.13 服务验证访问

访问首页:http://192.168.219.143:30223/

image.png

访问redis:http://192.168.219.143:30223/redis

image.png

访问postgresql:http://192.168.219.143:30223/postgresql

image.png

2.8.14 问题排查

数据的容器内的日志显示没有创建这个数据库!:

postgresql容器日志:

image.png

redis容器:

image.png

fastapi服务容器日志:

image.png

从上面的日志显示结果可以看出,我们的当前的组件启动其实都是没啥大的问题。

主要问题点是:

1-:我们的redis连接获取参数的过程出现了异常

2-:我们的postgresql数据库连接正常,但是要连接的数据库**ceshi**还没创建,所以范湖一了服务请求的处理异常。

解决这个两个问题,那么我们整个服务就运行正常了!!!

首先修改我们的redis,去除编码读取异常:

image.png

再修改数据库问题:使用默认的数据库postgres进行连接测试:

image.png

重新打包镜像,进行升级操作。

2.8.15 问题修复后的版本升级

--设置我们的升级策略:滚动升级还是替换升级。

image.png

image.png

2.8.16 版本升级操作步骤

  • 1:新版本的镜像打包
  • 2:新版本镜像上传到阿里云仓库
  • 3:再已启动的容器组里面进行升级指定的容器镜像的操作

修改好我们的代码后,全新的代码为

#!/usr/bin/evn python
# -*- coding: utf-8 -*-
"""
-------------------------------------------------
   文件名称 :     main
   文件功能描述 :   功能描述
   创建人 :       小钟同学
   创建时间 :          2021/8/2
-------------------------------------------------
   修改描述-2021/8/2:         
-------------------------------------------------
"""
from fastapi import FastAPI
import uvicorn
# 这里的aioredis2.0版本的变化很大
import aioredis
# 定义应用实例
app = FastAPI()


# =====
from pydantic import BaseSettings
class Settings(BaseSettings):
    # 后面是默认值,我这里是为了说明加上去的!!!!!!别介意!!!!!
    POSTGRESQL_PASSWORD: str = "没有环境变量的情况下的默认值--》没有密码"
    POSTGRESQL_HOST: str = "mypgdb"
    POSTGRESQL_DB: str = 'postgres'
    POSTGRESQL_USER: str = 'postgres'

    # 默认其实是我们的创建K8S服务的名称
    REDIS_HOST = 'myredis'

settings = Settings()

print(settings.POSTGRESQL_PASSWORD)
print(settings.POSTGRESQL_HOST)
print(settings.POSTGRESQL_DB)
print(settings.REDIS_HOST)

# 获取
async def get_redis_pool() :
    # 注意这个也是需要容器内才可以!---
    # redis = await aioredis.create_redis(address, password=password)
    # 会自动的复用链接,也就是自动的启用连接池
    redis =  aioredis.from_url("redis://{}".format(settings.REDIS_HOST), encoding="utf-8", decode_responses=True)
    return redis


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

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

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

    print(settings.POSTGRESQL_PASSWORD)
    print(settings.POSTGRESQL_HOST)
    print(settings.POSTGRESQL_DB)
    print(settings.REDIS_HOST)

    return {"小钟同学读取数据库示例": "首页访问测试!"}
    # return {"小钟同学读取数据库示例": "redis读取到的信息:{};数据库读取到的内容:{}".format(value,data)  }



@app.get("/redis")
async def read_root():
    print(settings.POSTGRESQL_PASSWORD)
    print(settings.POSTGRESQL_HOST)
    print(settings.POSTGRESQL_DB)
    print(settings.REDIS_HOST)

    await  app.state.redis.set('my-key', 'redis测试设置')
    value = await app.state.redis.get('my-key')
    return {"小钟同学读取redis:": "value %s"%(value)}


@app.get("/postgresql")
async def read_root():
    print(settings.POSTGRESQL_PASSWORD)
    print(settings.POSTGRESQL_HOST)
    print(settings.POSTGRESQL_DB)
    print(settings.REDIS_HOST)

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

    return {"小钟同学读取数据库示例postgresql": "database version : %s " % data}




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)

开始生成新的镜像

这里我生成的镜像的时候,直接的给镜像生成阿里云的指定的格式,不需要再打标签。

先查看我们的之前部署的版本是哪个?

 image: 'registry.cn-shenzhen.aliyuncs.com/zyx-xiaozhong/fastapi-k8s-app:v1.1.1'

那我们的现在生成一个新的V1.1.2版本的注意后面的 . 指的是当前目录下):

(docker_fastapi) D:\code\python\local_python\docker_kubesphere_fastapi>docker build -t registry.cn-shenzhen.aliyuncs.com/zyx-xiaozhong/fastapi-k8s-app:v1.1.2 .

新版本镜像上传到阿里云仓库

(docker_fastapi) D:\code\python\local_python\docker_kubesphere_fastapi>docker push  registry.cn-shenzhen.aliyuncs.com/zyx-xiaozhong/fastapi-k8s-app:v1.1.2

查看上传结果:

image.png

容器组里面进行升级指定的容器镜像的操作

应用负载-----工作负载-----选择我们的服务

image.png

编辑配置模板操作:

image.png

选择容器组,进行镜像修改:

image.png

进入到修改界面,编辑容器的地方,进行版本重新搜索升级:

image.png

修改一下我们的之前的一些环境变量的配置:

image.png

其他保持不变,然后直接的√,保存!进行确认!

新的容器则重新拉取中:

image.png

等待重新部署完成后:

image.png

2.8.17 版本升级后验证访问

重新的验证访问:

访问首页:http://192.168.219.143:30223/ image.png

访问redis:http://192.168.219.143:30223/redis image.png

访问postgresql:http://192.168.219.143:30223/postgresql image.png

从结果看。目前版本修复已完成了!!!完美!!!

以上是关于一个简单的服务部署的完整的流程示例!仅供参考!

结尾

END

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

掘金:juejin.cn/user/296393…

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

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

  • 1:本文相关描述主要是个人的认知和见解,如有不当之处,还望各位大佬指正。
  • 2:关于文章内容,部分内容参考自互联网整理,如有链接会声明标注;如没有及时标注备注的链接的,如有侵权请联系,我会立即删除处理哟。