-
前期准备
- 创建service account
apiVersion: v1
kind: ServiceAccount
metadata:
name: operation-platform
namespace: default
- 创建ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: all-namespaces-pod-reader
rules:
- apiGroups: [""]
resources: ["pods", "pods/log"]
verbs: ["get", "list", "watch"]
- apiGroups: ["apps"]
resources: ["deployments"]
verbs: ["get", "list", "watch", "create", "update", "delete"]
- apiGroups: [""]
resources: ["services"]
verbs: ["get", "list", "watch", "create", "update", "delete"]
- apiGroups: ["extensions", "networking.k8s.io"]
resources: ["ingresses"]
verbs: ["get", "list", "watch", "create", "update", "delete"]
- apiGroups: [""]
resources: ["nodes"]
verbs: ["get", "list", "watch"]
- apiGroups: [""]
resources: ["nodes/stats"]
verbs: ["get", "list", "watch"]
- apiGroups: ["metrics.k8s.io"]
resources: ["nodes"]
verbs: ["get", "list", "watch"]
- apiGroups: [""]
resources: ["nodes/proxy"]
verbs: ["get", "list", "watch", "create", "update", "delete"]
- apiGroups: [""]
resources: ["configmaps"]
verbs: ["get", "list", "watch", "create", "update", "delete"]
- 创建ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: all-namespaces-pod-reader
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: all-namespaces-pod-reader
subjects:
- kind: ServiceAccount
name: operation-platform
namespace: default
- 创建Secret
apiVersion: v1
kind: Secret
metadata:
name: operation-platform-token
namespace: default
annotations:
kubernetes.io/service-account.name: operation-platform
type: kubernetes.io/service-account-token
- 使用deployment部署服务
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: operation-platform
name: operation-platform
namespace: default
spec:
replicas: 1 #pod数量
selector:
matchLabels:
app: operation-platform
strategy: #升级策略(默认为滚动升级,不需要修改)
type: RollingUpdate
rollingUpdate:
maxSurge: 1 #滚动升级时会先启动1个pod
maxUnavailable: 0 #滚动更新时最大可以删除多少个pod
template: #定义pod
metadata:
labels:
app: operation-platform
logging: "true"
spec:
serviceAccountName: operation-platform
containers: #定义容器
- name: operation-platform
image: operation_platform_staging:latest
imagePullPolicy: Always
env:
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
ports:
- containerPort: 58180
name: http
resources:
limits: #容器可以使用的最大限制
memory: 256Mi
requests: #一个pod中容器运行需要的资源
cpu: 20m
memory: 96Mi
---
apiVersion: v1
kind: Service
metadata:
labels:
app: operation-platform
name: operation-platform
namespace: default
spec:
ports:
- port: 58180
name: http
protocol: TCP
targetPort: 58180
selector:
app: operation-platform
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: operation-platform
namespace: default
labels:
app: operation-platform
annotations:
nginx.ingress.kubernetes.io/configuration-snippet: |
add_header Access-Control-Allow-Origin '*' always;
add_header Access-Control-Allow-Credentials 'true' always;
add_header Access-Control-Allow-Methods 'POST, GET, PUT, DELETE, PATCH, OPTIONS' always;
add_header Access-Control-Allow-Headers '*' always;
if ($request_method = 'OPTIONS') {
return 204;
}
proxy_pass_request_headers on;
#Ingress Core Settings
cert-manager.io/cluster-issuer: letsencrypt-cloudflare
# 强制的从 HTTP 重定向刀 HTTPS
ingress.kubernetes.io/ssl-redirect: "true"
# 指定 Ingress Controller 的类型
kubernetes.io/ingress.class: "nginx"
nginx.ingress.kubernetes.io/use-regex: "true"
spec:
tls:
- hosts:
- "*.xxx.com"
- xxx.com
secretName: certificate-secret
rules:
- host: operation-platform-staging.xxx.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: operation-platform
port:
number: 58180
- 在服务器上启动kubectl apply -f deployment.yml
- 后端服务
import logging
import os
import time
import uvicorn
from fastapi import FastAPI,HTTPException
from fastapi.responses import StreamingResponse
from kubernetes import client, config, watch
from kubernetes.client import V1Deployment, V1ObjectMeta
app = FastAPI()
# 创建 logger 实例并设置日志级别
logger = logging.getLogger("myapp")
logger.setLevel(logging.DEBUG)
# 配置日志处理程序和格式
handler = logging.StreamHandler()
formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s")
handler.setFormatter(formatter)
logger.addHandler(handler)
@app.get("/token")
def get_service_account_token():
with open("/var/run/secrets/kubernetes.io/serviceaccount/token", "r") as f:
token = f.read()
return {"message": token}
@app.get("/health")
async def root():
return {"message": "Hello World"}
@app.get("/service-account")
def get_service_account_name():
config.load_incluster_config()
api_instance = client.CoreV1Api()
# 从挂载的文件中读取命名空间
with open("/var/run/secrets/kubernetes.io/serviceaccount/namespace", "r") as f:
namespace = f.read()
# 获取当前 Pod 名称(从环境变量中读取)
pod_name = os.environ.get("POD_NAME")
# 使用 Kubernetes API 获取 Pod 详细信息
pod = api_instance.read_namespaced_pod(pod_name, namespace)
# 从 Pod 详细信息中获取 ServiceAccount 名称
service_account_name = pod.spec.service_account_name
return {"message": service_account_name, "namespace": namespace, "pod_name": pod_name}
@app.get("/pods-info/{namespace}/pod/{pod_name}")
async def get_pod_detail(namespace: str, pod_name: str):
# 加载配置并创建 API 实例
config.load_incluster_config()
api_instance = client.CoreV1Api()
# 获取指定的 Pod
pod_obj = api_instance.read_namespaced_pod(pod_name, namespace)
# 提取 Pod 的名称、运行时间和镜像
name = pod_obj.metadata.name
run_time = pod_obj.status.start_time
images = [container.image for container in pod_obj.spec.containers]
return {"name": name, "run_time": run_time, "images": images}
@app.get("/pods-info/{namespace}/deployment/{deployment}")
async def get_pods_info(namespace: str, deployment: str):
# 加载配置并创建 API 实例
config.load_incluster_config()
api_instance = client.CoreV1Api()
apps_v1_api_instance = client.AppsV1Api()
# 获取 Deployment
deployment_obj = apps_v1_api_instance.read_namespaced_deployment(deployment, namespace)
# 使用 Deployment 的 label 选择器过滤 Pod 列表
label_selector = ','.join([f"{k}={v}" for k, v in deployment_obj.spec.selector.match_labels.items()])
pods = api_instance.list_namespaced_pod(namespace, label_selector=label_selector)
pod_info = []
for pod in pods.items:
pod_info.append({"name": pod.metadata.name, "status": pod.status.phase, "run_time": pod.status.start_time})
return pod_info
@app.get("/logs/{namespace}/pod/{pod_name}")
async def get_pod_logs(namespace: str, pod_name: str):
# Load config and create API instance
config.load_incluster_config()
api_instance = client.CoreV1Api()
pod_logs = api_instance.read_namespaced_pod_log(pod_name, namespace)
return {"logs": pod_logs}
@app.post("/deploy/{namespace}")
async def create_deployment(namespace: str, deployment_info: dict):
# Load config and create API instance
config.load_incluster_config()
apps_v1_api_instance = client.AppsV1Api()
# Extract deployment information from the request
deployment_name = deployment_info["name"]
image = deployment_info["image"]
replicas = deployment_info["replicas"]
# Validate input data
if not (deployment_name and image and replicas):
raise HTTPException(status_code=400, detail="Invalid deployment information provided")
# Create the Deployment object
deployment = V1Deployment(
metadata=V1ObjectMeta(name=deployment_name),
spec={
"replicas": replicas,
"selector": {"matchLabels": {"app": deployment_name}},
"template": {
"metadata": {"labels": {"app": deployment_name}},
"spec": {"containers": [{"name": deployment_name, "image": image}]},
},
},
)
# Create the Deployment in the specified namespace
try:
created_deployment = apps_v1_api_instance.create_namespaced_deployment(namespace, deployment)
return {"message": f"Deployment '{deployment_name}' created successfully",
"deployment": created_deployment.to_dict()}
except client.exceptions.ApiException as e:
raise HTTPException(status_code=400, detail=f"Error creating deployment: {e}")
if __name__ == "__main__":
uvicorn.run(app, host="0.0.0.0", port=58180)
2.使用
curl 127.0.0.1:58180/health