在 Kubernetes 中调试 uWSGI

标签 debugging nginx flask kubernetes uwsgi

我有一对 kubernetes pod ,一个用于 nginx一个用于 Python Flask + uWSGI .我已经在 docker-compose 本地测试了我的设置,并且运行良好,但是在部署到 kubernetes 之后不知何故,两者之间似乎没有任何沟通。最终结果是我在尝试到达我的位置时收到 502 网关错误。

所以我的问题并不是我的设置出了什么问题,而是我可以使用哪些工具来调试这个场景。是否有 uwsgi 的测试客户端?我可以使用 ncat 吗?我似乎没有从 nginx 得到任何有用的日志输出,我也不知道 uwsgi 是否有日志。

我该如何调试呢?

作为引用,这是我的 nginx 位置:

location / {
        # Trick to avoid nginx aborting at startup (set server in variable)
        set $upstream_server ${APP_SERVER};

        include            uwsgi_params;
        uwsgi_pass         $upstream_server;
        uwsgi_read_timeout 300;
        uwsgi_intercept_errors on;
}

这是我的 wsgi.ini:
[uwsgi]
module = my_app.app
callable = app
master = true
processes = 5
socket = 0.0.0.0:5000
die-on-term = true

uid = www-data
gid = www-data

这是 nginx 的 kubernetes deployment.yaml:
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    service: nginx
  name: nginx
spec:
  replicas: 1
  revisionHistoryLimit: 2
  selector:
    matchLabels:
      service: nginx
  strategy:
    type: Recreate
  template:
    metadata:
      labels:
        service: nginx
    spec:
      imagePullSecrets:
      - name: docker-reg
      containers:
      - name: nginx
        image: <custom image url>
        imagePullPolicy: Always
        env:
          - name: APP_SERVER
            valueFrom:
              secretKeyRef:
                name: my-environment-config
                key: APP_SERVER
          - name: FK_SERVER_NAME
            valueFrom:
              secretKeyRef:
                name: my-environment-config
                key: SERVER_NAME
        ports:
        - containerPort: 80
        - containerPort: 10443
        - containerPort: 10090
        resources:
          requests:
            cpu: 1m
            memory: 200Mi
        volumeMounts:
        - mountPath: /etc/letsencrypt
          name: my-storage
          subPath: nginx
        - mountPath: /dev/shm
          name: dshm
      restartPolicy: Always
      volumes:
      - name: my-storage
        persistentVolumeClaim:
          claimName: my-storage-claim-nginx
      - name: dshm
        emptyDir:
          medium: Memory

这是 nginx 的 kubernetes service.yaml:
apiVersion: v1
kind: Service
metadata:
  labels:
    service: nginx
  name: nginx
spec:
  type: LoadBalancer
  ports:
  - name: "nginx-port-80"
    port: 80
    targetPort: 80
    protocol: TCP
  - name: "nginx-port-443"
    port: 443
    targetPort: 10443
    protocol: TCP
  - name: "nginx-port-10090"
    port: 10090
    targetPort: 10090
    protocol: TCP
  selector:
    service: nginx

这是 python flask 的 kubernetes deployment.yaml:
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    service: my-app
  name: my-app
spec:
  replicas: 1
  revisionHistoryLimit: 2
  selector:
    matchLabels:
      service: my-app
  strategy:
    type: Recreate
  template:
    metadata:
      labels:
        service: my-app
    spec:
      imagePullSecrets:
      - name: docker-reg
      containers:
      - name: my-app
        image: <custom image url>
        imagePullPolicy: Always
        ports:
        - containerPort: 5000
        resources:
          requests:
            cpu: 1m
            memory: 100Mi
        volumeMounts:
        - name: merchbot-storage
          mountPath: /app/data
          subPath: my-app
        - name: dshm
          mountPath: /dev/shm
        - name: local-config
          mountPath: /app/secrets/local_config.json
          subPath: merchbot-local-config-test.json
      restartPolicy: Always
      volumes:
      - name: merchbot-storage
        persistentVolumeClaim:
          claimName: my-storage-claim-app
      - name: dshm
        emptyDir:
          medium: Memory
      - name: local-config
        secret:
          secretName: my-app-local-config

这是 nginx 的 kubernetes service.yaml:
apiVersion: v1
kind: Service
metadata:
  labels:
    service: my-app
  name: my-app
spec:
  ports:
  - name: "my-app-port-5000"
    port: 5000
    targetPort: 5000
  selector:
    service: my-app

最佳答案

在 Kubernetes 中调试与在外部调试没有太大区别,只是需要为 Kubernetes 世界覆盖一些概念。

Kubernetes 中的 Pod 是您在概念上将其视为 VM 世界中的主机。在 Pod 中运行的每个容器都会在 localhost 上看到彼此的服务。从那里,一个 Pod 到其他任何东西都将涉及网络连接(即使端点是节点本地的)。因此,开始在 localhost 上使用服务进行测试,然后通过 pod IP、服务 IP、服务名称来解决问题。

一些复杂性来自于容器中提供的调试工具。通常,容器构建得很纤薄,并且没有所有可用的东西。因此,您要么需要在容器运行时安装工具(如果可以的话),要么构建一个特殊的“调试”容器,您可以在同一环境中按需部署。您始终可以从也具有访问权限的集群节点回退到测试。

如果你有可用的 python,你可以 test with uswgi_curl

pip install uwsgi-tools
uwsgi_curl hostname:port /path

否则 nc/curl在一定程度上就足够了。

Pod 到本地主机

第一步是确保容器本身响应。在这种情况下,您可能有 python/pip 可供使用 uwsgi_curl
kubectl exec -ti my-app-XXXX-XXXX sh
nc -v localhost 5000
uwsgi_curl localhost:5000 /path

Pod 到 Pod/服务

接下来包括 Kubernetes 网络。从 IP 开始,以名称结束。

不太可能有python在这里,甚至nc但我认为测试环境变量在这里很重要:
kubectl exec -ti nginx-XXXX-XXXX sh
nc -v my-app-pod-IP 5000
nc -v my-app-service-IP 5000
nc -v my-app-service-name 5000

echo $APP_SERVER
echo $FK_SERVER_NAME
nc -v $APP_SERVER 5000
# or 
uwsgi_curl $APP_SERVER:5000 /path

调试 Pod 到 Pod/服务

如果您确实需要使用调试 pod,请尝试尽可能模仿您正在测试的 pod。拥有一个通用的调试 pod/deployment 来快速测试任何东西是很棒的,但如果这不能揭示问题,您可能需要自定义部署以更紧密地模拟您正在测试的 pod。

在这种情况下,环境变量会在连接设置中发挥作用,因此应该为调试 pod 模拟。

节点到 Pod/服务

Pods/Services 可从集群节点获得(如果您没有使用限制性网络策略),因此通常快速测试是检查 Pods/Services 是否从那里工作:
nc -v <pod_ip> <container_port>
nc -v <service_ip> <service_port>
nc -v <service__dns> <service_port>

在这种情况下:
nc -v <my_app_pod_ip> 5000
nc -v <my_app_service_ip> 5000
nc -v my-app.svc.<namespace>.cluster.local 5000

关于在 Kubernetes 中调试 uWSGI,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60385044/

相关文章:

c++ - 当指向基类的指针指向特定子类时有条件地中断的断点

wordpress - LEMP + wordpress 文件权限能够编辑、升级和使用 sftp 客户端

python - Flask - Apscheduler 无法调用执行数据库命令的函数

python - peewee DoubleField 的默认值不会反射(reflect)在 MySQL 数据库中

python - Flask:使用 POST 方法存储值并使用 GET 方法检索它

python - VScode运行代码选择

c - 使用 GDB 单步调试多线程应用程序

java - 有人可以解释为什么会出现这样的结果吗?

swift - iOS 12 wkwebview 无法使用重定向?

ruby-on-rails - Nginx ssl_protocol 设置不起作用