快速开始

本文档将帮助您快速了解如何创建 PyPI connector 以连接到 PyPI registry,并安全地执行 twinepip 操作,而无需直接处理凭据。

我们将创建一个 PyPI connector,并使用它执行 twine uploadpip install,无需在客户端直接处理凭据。

预计阅读时间

15 分钟

前提条件

  • 已安装 Connectors 系统(Operator、ConnectorsCore 和 ConnectorsPyPI 组件)的 Kubernetes 集群。有关安装这些组件的详细信息,请参见安装指南
  • PyPI registry 地址和凭据
  • Kubernetes 和 PyPI 的基础知识

流程概览

步骤操作说明
1创建 Namespace设置一个专用的命名空间用于演示
2配置 PyPI Registry 凭据和 Connector创建认证 Secret 和 PyPI connector 资源
3创建执行 twine upload 的 PyPI Job创建一个通过 connector 执行 twine upload 的 Job
4创建执行 pip install 的 PyPI Job创建一个通过 connector 执行 pip install 的 Job

操作步骤

第 1 步:创建 Namespace

为本次演示创建一个专用的命名空间:

kubectl create ns connectors-pypi-demo

第 2 步:创建 PyPI Registry 凭据和 Connector

创建包含 PyPI registry 凭据的 Secret 和 PyPI connector 资源。您的 PyPI registry 应该是一个仓库。

有关创建和配置 connector 的详细信息,请参阅Connectors 快速开始指南

cat <<EOF | kubectl apply -n connectors-pypi-demo -f -
kind: Secret
apiVersion: v1
metadata:
  name: pypi-registry-secret
type: kubernetes.io/basic-auth
stringData:
  username: your-registry-username # 替换为您的 PyPI registry 用户名
  password: your-registry-password # 替换为您的 PyPI registry 密码
---
apiVersion: connectors.alauda.io/v1alpha1
kind: Connector
metadata:
  name: pypi-connector
spec:
  connectorClassName: pypi
  address: https://nexus.example.com/repository/pypi # 替换为您的 PyPI 仓库地址,我们将向此仓库部署包。
  auth:
    name: basicAuth
    secretRef:
      name: pypi-registry-secret
EOF

验证 connector 是否处于 "Ready" 状态:

kubectl get connector pypi-connector -n connectors-pypi-demo

输出应显示:

NAME              CLASS   ADDRESS                                                    READY   REASON   AGE
pypi-connector   pypi   https://nexus.example.com/repository/pypi   True             10s

第 3 步:创建执行 twine upload 的 Job

创建一个使用 connector 执行 PyPI 操作的 Job:

cat <<'EOF' | kubectl apply -n connectors-pypi-demo -f -
apiVersion: batch/v1
kind: Job
metadata:
  name: twine-upload
spec:
  backoffLimit: 0
  template:
    spec:
      restartPolicy: Never
      containers:
      - name: twine
        image: python:3-bookworm
        imagePullPolicy: IfNotPresent
        command:
        - "sh"
        - "-c"
        - |
          set -ex
          pip install --upgrade pip build twine
          git clone https://github.com/pypa/sampleproject.git
          cd sampleproject
          python -m build
          python3 -m twine upload --repository connectors-pypi dist/*
        volumeMounts:
        - name: pypirc
          mountPath: /root/.pypirc
          subPath: .pypirc
      volumes:
      - name: pypirc
        csi:
          readOnly: true
          driver: connectors-csi
          volumeAttributes:
            connector.name: "pypi-connector"
            configuration.names: "pypirc"
EOF

输出应显示:

...
Successfully built sampleproject-4.0.0.tar.gz and sampleproject-4.0.0-py3-none-any.whl
+ python3 -m twine upload --repository connectors-pypi dist/sampleproject-4.0.0-py3-none-any.whl dist/sampleproject-4.0.0.tar.gz
Uploading distributions to 
http://c-pypi-connector.connectors-pypi-demo.svc.cluster.local/
Uploading sampleproject-4.0.0-py3-none-any.whl
100% ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 12.7/12.7 kB • 00:00 • ?
Uploading sampleproject-4.0.0.tar.gz
100% ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 13.8/13.8 kB • 00:00 • ?

关键设置

volumes[].volumeAttributes

  • connector.name:您的 pypi connector 名称
  • configuration.names:设置为 "pypirc",引用了 pypi connectorClass 中定义的特定配置模板。该模板用于生成带有适当认证设置的 "pypirc" 文件。

第 4 步:创建执行 pip install 的 PyPI Job

创建一个使用 connector 执行 PyPI 操作的 Job:

cat <<'EOF' | kubectl apply -n connectors-pypi-demo -f -
apiVersion: batch/v1
kind: Job
metadata:
  name: pip-install
spec:
  backoffLimit: 0
  template:
    spec:
      restartPolicy: Never
      containers:
      - name: pip
        image: python:3-bookworm
        imagePullPolicy: IfNotPresent
        command:
        - "sh"
        - "-c"
        - |
          set -ex
          pip install --upgrade sampleproject --no-deps
        volumeMounts:
        - name: pipconf
          mountPath: /root/.pip/pip.conf
          subPath: pip.conf
      volumes:
      - name: pipconf
        csi:
          readOnly: true
          driver: connectors-csi
          volumeAttributes:
            connector.name: "pypi-connector"
            configuration.names: "pipconf"
EOF

输出应显示:

+ pip install --upgrade sampleproject --no-deps
Looking in indexes: http://connectors-pypi-demo-pypi-connector:****@c-pypi-connector.connectors-pypi-demo.svc.cluster.local/simple/
Collecting sampleproject
  Downloading http://c-pypi-connector.connectors-pypi-demo.svc.cluster.local/packages/sampleproject/4.0.0/sampleproject-4.0.0-py3-none-any.whl (4.7 kB)
Installing collected packages: sampleproject
Successfully installed sampleproject-4.0.0

底层原理

PyPI connector 的工作原理:

  1. 创建一个代理服务,位于您的 PyPI 客户端和目标 PyPI registry 之间
  2. 在请求通过代理时注入认证信息
  3. 为客户端提供 pip.conf.pypirc 文件,以便通过代理执行 PyPI 操作

为了演示该机制,我们来查看生成的 pip.conf.pypirc 文件:

cat <<EOF | kubectl apply -n connectors-pypi-demo -f -
apiVersion: v1
kind: Pod
metadata:
  name: inspect-pypi-deploy
spec:
  restartPolicy: Never
  containers:
  - name: pip
    image: docker-mirrors.alauda.cn/library/python:3-bookworm # 替换为包含 python 的镜像
    command: ["sleep", "3600"]
    volumeMounts:
    - name: pipconf
      mountPath: /root/.pip/pip.conf
      subPath: pip.conf
    - name: pypirc
      mountPath: /root/.pypirc
      subPath: .pypirc
  volumes:
  - name: pipconf
    csi:
      readOnly: true
      driver: connectors-csi
      volumeAttributes:
        connector.name: "pypi-connector"
        configuration.names: "pipconf"
  - name: pypirc
    csi:
      readOnly: true
      driver: connectors-csi
      volumeAttributes:
        connector.name: "pypi-connector"
        configuration.names: "pypirc"
EOF

查看 /root/.pip/pip.conf/root/.pypirc 中生成的文件:

$ kubectl exec -it inspect-pypi-deploy -n connectors-pypi-demo -- ls -l /root/.pip/pip.conf /root/.pypirc
-r--r--r-- 1 root root 1276 Oct  6 04:07 /root/.pip/pip.conf
-r--r--r-- 1 root root 1251 Oct  6 04:07 /root/.pypirc

查看生成的 pip.conf.pypirc 文件内容:

$ kubectl exec -it inspect-pypi-deploy -n connectors-pypi-demo -- cat /root/.pip/pip.conf
[global]
index-url = http://connectors-pypi-demo-pypi-connector:eyJhbGciOiJSUzI1NiIsImtpZCI6IklNVm9ZVWR6Y05PNWotUlRCQWRyTlVPak05WWxTanIwYnNJSjdtRTlHcXMifQ.eyJhdWQiOlsiaHR0cHM6Ly9rdWJlcm5ldGVzLmRlZmF1bHQuc3ZjLmNsdXN0ZXIubG9jYWwiLCJodHRwOi8vYy1weXBpLWNvbm5lY3Rvci5jb25uZWN0b3JzLXB5cGktZGVtby5zdmMuY2x1c3Rlci5sb2NhbCJdLCJleHAiOjE3NTk3MjU0NTIsImlhdCI6MTc1OTcyMzY1MiwiaXNzIjoiaHR0cHM6Ly9rdWJlcm5ldGVzLmRlZmF1bHQuc3ZjLmNsdXN0ZXIubG9jYWwiLCJqdGkiOiI4NjVhZmIwZi0xYTJkLTRiODAtOWY4Mi03YjMxOWUxNzFmYzIiLCJrdWJlcm5ldGVzLmlvIjp7Im5hbWVzcGFjZSI6ImNvbm5lY3RvcnMtcHlwaS1kZW1vIiwic2VydmljZWFjY291bnQiOnsibmFtZSI6ImRlZmF1bHQiLCJ1aWQiOiI4ZjMyMzhjNC0wMTFjLTRkZTktOTcxYS1lYTRkZTQ2NTQyZmEifX0sIm5iZiI6MTc1OTcyMzY1Miwic3ViIjoic3lzdGVtOnNlcnZpY2VhY2NvdW50OmNvbm5lY3RvcnMtcHlwaS1kZW1vOmRlZmF1bHQifQ.BPbpWNz1A4JUjKkQFgeglIoW3YKydMiR_0r2V3R7awSnac6lQiEMrmJQ2MgAKbrzysmi_tfku6bLjk7Jkq_OmPdSwiwFvh6Ixxpe2lk7Ej10hCibxNTrqnsPVV9upS1WyKaci7nwvtV5qH2smjcpNB38sjX-pi5nCblGKXbj4Gt0F11-OVyPOD6FJayhEYmT3bi-GXJGi3da7vYR1v-L3c3JF4RiV4xQ_FpnBgdzD9_C9WZuXAHSp8oXxzGRra7kqhjpCO10GMmExvT9mfKr-z5f1CZdMcbsiGRkxkZ6EH-W8Q4DQ09a3Thnmq_lBd5xriwqldBEN8_1Cnh6A70Wrw@c-pypi-connector.connectors-pypi-demo.svc.cluster.local/simple/
timeout = 30

[install]
trusted-host = c-pypi-connector.connectors-pypi-demo.svc.cluster.local

$ kubectl exec -it inspect-pypi-deploy -n connectors-pypi-demo -- cat /root/.pypirc
[distutils]
index-servers = connectors-pypi

[connectors-pypi]
repository = http://c-pypi-connector.connectors-pypi-demo.svc.cluster.local/ # 代理地址
username = connectors-pypi-demo-pypi-connector # pypi 代理的用户名
password = eyJhbGciOiJSUzI1NiIsImtpZCI6IklNVm9ZVWR6Y05PNWotUlRCQWRyTlVPak05WWxTanIwYnNJSjdtRTlHcXMifQ.eyJhdWQiOlsiaHR0cHM6Ly9rdWJlcm5ldGVzLmRlZmF1bHQuc3ZjLmNsdXN0ZXIubG9jYWwiLCJodHRwOi8vYy1weXBpLWNvbm5lY3Rvci5jb25uZWN0b3JzLXB5cGktZGVtby5zdmMuY2x1c3Rlci5sb2NhbCJdLCJleHAiOjE3NTk3MjU0NTIsImlhdCI6MTc1OTcyMzY1MiwiaXNzIjoiaHR0cHM6Ly9rdWJlcm5ldGVzLmRlZmF1bHQuc3ZjLmNsdXN0ZXIubG9jYWwiLCJqdGkiOiIxNmFmM2Q0Yi1hYjUyLTQwNDgtYjAxYS1hMGRmZTM2MDI1NTAiLCJrdWJlcm5ldGVzLmlvIjp7Im5hbWVzcGFjZSI6ImNvbm5lY3RvcnMtcHlwaS1kZW1vIiwic2VydmljZWFjY291bnQiOnsibmFtZSI6ImRlZmF1bHQiLCJ1aWQiOiI4ZjMyMzhjNC0wMTFjLTRkZTktOTcxYS1lYTRkZTQ2NTQyZmEifX0sIm5iZiI6MTc1OTcyMzY1Miwic3ViIjoic3lzdGVtOnNlcnZpY2VhY2NvdW50OmNvbm5lY3RvcnMtcHlwaS1kZW1vOmRlZmF1bHQifQ.U3SpoP9QL1HsxENBcSiC-0vPG2BME6qEzflv6OXSlu1KiU8iGejfcAW-OvTDKwVJq2rwjJf2mQkEIs7aySrJAJ241dAoqEQ68pZ3zpZwcxNquuK7q7jP1PSNnupw4h_T250m5LfUenp3p3bir-TkxZbmATNUCHeVyrKxIJQj8f0UuZZ5CF_gBBUSOU8geI70oTwmfE7cVExd75UttUHWOFkP-wQYFdQG1Mq05DA2xCvPt0gajmOIBLTTjKVahY5v9nBfJsnJHNtRu12xG-dFULpy3BVU0wEkH8pWA6iegXw4xNj2nB6rGK4EIvPrcMZYXX_Fpnigucnw_0wtwE-syg # 代理的令牌。

认证流程

inspect-pypi-deploy Pod 不包含任何原始集群令牌。当 maven 向 maven registry 发起 HTTPS 请求时,代理服务器拦截这些请求,从 pypi-connector 注入认证凭据,并将认证后的请求转发到后端 pypi registry 服务器。

设置卷

pip.conf.pypirc 文件通过 Connectors CSI Driver 挂载到 Pod 中。

  volumes:
  - name: pipconf
    csi:
      readOnly: true
      driver: connectors-csi
      volumeAttributes:
        connector.name: "pypi-connector"
        configuration.names: "pipconf"
  - name: pypirc
    csi:
      readOnly: true
      driver: connectors-csi
      volumeAttributes:
        connector.name: "pypi-connector"
        configuration.names: "pypirc"

在上述示例中,pip.conf.pypirc 文件通过 Connectors CSI Driver 挂载到 Pod 中。

  • pip.conf.pypirc 文件使用 connector 代理作为 PyPI registry,当 PyPI 客户端请求该地址时,代理会将请求转发到后端 pypi registry,并在请求通过代理时注入认证信息。

有关 volumes 参数,请参阅 PyPI Connector Concepts 文档中的使用 Connectors CSI Driver 挂载 pip.conf 和 .pypirc 文件

延伸阅读

成功使用 maven connector 执行 mvn deploy 操作后,您可以:

参考资料