* [Fix] Relocate User Permanent SSH Public Key queries to DevcontainerService Layer * [Fix] Add Unix Timestamps in DB table `devstar_devcontainer` * [Feature] Tencent NAT port forwarding * [Doc] k8s Operator RBAC: ServiceAccount, ClusterRole, ClusterRoleBinding, etc. * [fix] k8s Operator Reconciler error while converting YAML to JSON * [Doc] Added DevStar API Doc * [fix] detailed errors while listing user devcontainers * [fix] Invalid metadata.labels: value must be no more than 63 characters
18 KiB
date, title, slug, sidebar_position, toc, draft, aliases, menu
| date | title | slug | sidebar_position | toc | draft | aliases | menu | |||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 2018-06-24:00:00+02:00 | DevStar API 使用指南 | api-devstar | 40 | false | false |
|
|
DevStar API 使用指南
1. 生成临时 SSH 密钥对
请求方式:
GET /api/devstar_ssh/key_pair/new_temp?_=${CurrentTimestamp}
| 请求参数 | 类型 | 含义 | 作用 |
|---|---|---|---|
_ |
整数 | 匿名参数,存放任意值(推荐使用当前的时间戳) | 用于防止 HTTP GET 请求被缓存,保证每次请求都能到达服务器端 |
| 请求头 | 载荷 | 作用 |
|---|---|---|
Authorization |
token ${accessToken} |
登录凭证,用于标识用户身份,防止接口被滥用 |
Content-Type |
application/json |
用于标识返回数据格式是 JSON |
响应格式(操作成功):
{
"code": 0,
"msg": "操作成功",
"data": {
"KeySize": "2048",
"privateKeyPem": "-----BEGIN RSA PRIVATE KEY-----\n......\n-----END RSA PRIVATE KEY-----\n",
"publicKeyFingerprint": "ssh-rsa AAAAB3N......\n",
"publicKeyPem": "-----BEGIN PUBLIC KEY-----\n......\n-----END PUBLIC KEY-----\n"
}
}
响应数据说明:
code: 错误代码,0表示无错误msg: 错误代码含义,以人类可读的方式描述错误代码的具体含义,0代表操作成功data: 返回数据KeySize: 当前系统使用的密钥长度,默认值 2048,可在 app.ini 文件中的devstar.ssh_key_pair.KEY_SIZE指定大于 2048 位的密钥长度privateKeyPem: PEM 格式的 RSA 私钥,可保存于客户端目录~/.ssh/id_rsa用于 SSH 登录使用的 RSA 私钥publicKeyPem: PEM 格式的 RSA 公钥publicKeyFingerprint: SSH 格式的 RSA 公钥,可保存于服务器目录~/.ssh/authorized_keys用于 SSH 登录使用的 RSA 公钥
响应格式(操作失败:未登录):
{
"code": 1,
"msg": "未登录,禁止访问"
}
响应数据说明:
code: 错误代码,1表示发生错误msg: 错误代码含义,以人类可读的方式描述错误代码1具体含义: 未登录,禁止访问
响应格式(操作失败:发生内部错误):
{
"code": 12001,
"msg": "生成 SSH 密钥对失败",
"data": {
"ErrorMsg": "Failed to ${ACTION_NAME} for SSH Key: ${ACTION_RESULT}",
"KeySize": "2048"
}
}
响应数据说明:
code: 错误代码msg: 错误代码含义,以人类可读的方式描述错误代码具体含义data: 对错误信息进一步描述KeySize: 当前系统使用的密钥长度,默认值 2048,可在 app.ini 文件中的devstar.ssh_key_pair.KEY_SIZE指定大于 2048 位的密钥长度ErrorMsg: API 调用过程中返回错误信息封装,其中ACTION_NAME表示具体操作步骤,ACTION_RESULT表示具体操作步骤结果
2. DevContainer 管理
DevContainer 是指可以通过 SSH 连接的远程服务器开发容器环境
在 k8s 中,DevContainer 被定义为 CRD 资源
DevcontainerApp,具体包含如下资源:
StatefulSet: 用于管理有状态应用Service:用于向集群外暴露 DevContainer,提供服务访问k8s CRD 资源
DevcontainerApp通过 k8s Operator 机制进行管理,可以通过下列 kubectl 命令查看:kubectl get deployment -n devcontainer-operator-system devcontainer-operator-controller-manager # NAME READY UP-TO-DATE AVAILABLE AGE # devcontainer-operator-controller-manager 1/1 1 1 2d17h对于部署在 k8s 上的 DevContainer,SSH 连接依此经过:
- 云服务厂商的 NAT 路由器
- k8s NodePort Service
- k8s Pod
- k8s Pod 中运行的 OpenSSH 服务器
对 DevContainer 管理主要包括下述操作:
- 创建一个新的 DevContainer
- 查看当前用户创建的所有 DevContainer
- 获取 DevContainer 打开信息
- 删除 DevContainer
2.1 创建 DevContainer
请求方式:
POST /api/devcontainer
| 请求参数 | 类型 | 含义 | 作用 |
|---|---|---|---|
repoId |
字符串 | 仓库 ID | 标识当前用户希望创建 DevContainer 所关联的 仓库 |
sshPublicKeyList |
字符串数组 | SSH公钥列表 | 标识用户除了使用 DevStar 后台添加的用户永久 SSH 公钥外,该 DevContainer SSH 会话使用额外的临时 SSH 公钥列表 |
注:上述请求参数需要以 JSON 格式封装在 POST 请求 Body 域:
{
"repoId": "${REPO_ID}",
"sshPublicKeyList": [
"ssh-rsa AAAAB3N......Pn9TWOE= SSH_PUBLIC_KEY_1",
"ssh-rsa AAAAB3N......Pn9TWOE= SSH_PUBLIC_KEY_2",
]
}
| 请求头 | 载荷 | 作用 |
|---|---|---|
Authorization |
token ${accessToken} |
登录凭证,用于标识用户身份,防止接口被滥用 |
Content-Type |
application/json |
用于标识返回数据格式是 JSON |
响应格式(操作成功):
{
"code": 0,
"msg": "操作成功"
}
响应数据说明:
code: 错误代码,0表示无错误msg: 错误代码含义,以人类可读的方式描述错误代码的具体含义,0代表创建 DevContainer 成功
响应格式(操作失败:未登录):
{
"code": 1,
"msg": "未登录,禁止访问"
}
响应数据说明:
code: 错误代码msg: 错误代码含义,以人类可读的方式描述错误代码具体含义
响应格式(操作失败:数据校验失败):
{
"code": 11002,
"msg": "无效参数",
"data": {
"ErrorMsg": "......"
}
}
响应数据说明:
code: 错误代码msg: 错误代码含义,以人类可读的方式描述错误代码具体含义data: 对错误信息进一步描述ErrorMsg: 描述数据校验失败的报错信息(可能是传入repoId不是数字,或者repoId字符串长度过长)
响应格式(操作失败:发生内部错误):
{
"code": 11003,
"msg": "创建 DevContainer 失败",
"data": {
"ErrorMsg": "Failed to ${ACTION_NAME} in DevContainer Service: ${ACTION_RESULT}"
}
}
响应数据说明:
code: 错误代码msg: 错误代码含义,以人类可读的方式描述错误代码具体含义data: 对错误信息进一步描述ErrorMsg: 描述数据校验失败的报错信息,${ACTION_NAME}表示操作名称,${ACTION_RESULT}表示操作结果
2.2 获取当前登录用户的 DevContainer 列表
请求方式:
GET /api/devcontainer/user?_=${CurrentTimestamp}&page=1&page_size=2
| 请求参数 | 类型 | 含义 | 作用 |
|---|---|---|---|
_ |
整数 | 匿名参数,存放任意值(推荐使用当前的时间戳) | 用于防止 HTTP GET 请求被缓存,保证每次请求都能到达服务器端 |
page |
整数 | 当前所在页码(默认值 1) |
用于分页展示 DevContainer |
page_size |
整数 | 当前所在页码(必须小于等于默认值:app.ini 中的 ui.admin.DEV_CONTAINERS_PAGING_NUM) |
用于控制每页展示 DevContainer 个数 |
| 请求头 | 载荷 | 作用 |
|---|---|---|
Authorization |
token ${accessToken} |
登录凭证,用于标识用户身份,防止接口被滥用 |
Content-Type |
application/json |
用于标识返回数据格式是 JSON |
响应格式(操作成功):
{
"code": 0,
"msg": "操作成功",
"data": {
"userId": 5,
"username": "daimingchen",
"devContainers": [
{
"devContainerId": 41,
"devContainerName": "daimingchen-devstar-fa72bebd8bb611ef9c1a4e1bce2a7080",
"devContainerHost": "devcontainer.devstar.cn",
"devContainerUsername": "root",
"devContainerWorkDir": "/data",
"repoId": 3,
"repoName": "devstar",
"repo_owner_name": "devstar",
"repo_link": "/devstar/devstar",
"repoDescription": "DevStar Studio"
},
{
"devContainerId": 38,
"devContainerName": "daimingchen-12-dcbb9c5b8a0611ef9c1a4e1bce2a7080",
"devContainerHost": "devcontainer.devstar.cn",
"devContainerUsername": "root",
"devContainerWorkDir": "/data",
"repoId": 19,
"repoName": "12",
"repo_owner_name": "leviyanx",
"repo_link": "/leviyanx/12"
}
],
"page": 1,
"pageSize": 30,
"pageTotalNum": 1,
"itemTotalNum": 2
}
}
响应数据说明:
code: 错误代码,0表示无错误msg: 错误代码含义,以人类可读的方式描述错误代码的具体含义,0代表获取用户 DevContainer 列表成功data: 返回数据userId: 当前已登录用户 IDusername: 当前已登录用户名itemTotalNum: 当前用户 DevContainer 总数pageSize: 每个页面最多展示 DevContainer 个数page: 当前页码devContainers: 当前页面 DevContainer 列表pageTotalNum: 总页数
其中,对于 devContainers 中的每个元素,具体含义如下:
| 字段名称 | 类型 | 含义 |
|---|---|---|
devContainerId |
整数 | DevContainer ID |
devContainerName |
字符串 | 唯一标识 DevContainer 名称 |
devContainerHost |
字符串 | SSH 连接主机的 IP 或者 DNS 域名 |
devContainerUsername |
字符串 | SSH 登录用户名 |
devContainerWorkDir |
字符串 | SSH 登录成功后工作目录 |
repoId |
整数 | DevContainer 关联的仓库的 ID |
repoName |
字符串 | DevContainer 关联的仓库的名称 |
repo_owner_name |
字符串 | DevContainer 关联的仓库的所有者用户 ID |
repo_link |
字符串 | DevContainer 关联的仓库的访问绝对地址 URL |
repoDescription |
字符串 | DevContainer 关联的仓库的描述信息(可选字段) |
响应格式(操作失败:未登录):
{
"code": 1,
"msg": "未登录,禁止访问"
}
响应数据说明:
code: 错误代码msg: 错误代码含义,以人类可读的方式描述错误代码具体含义
响应格式(操作失败:发生内部错误):
{
"code": 11006,
"msg": "查询用户 DevContainer 列表失败",
"data": {
"ErrorMsg": "Failed to ${ACTION_NAME} in DevStar DevContainer DB: ${ACTION_RESULT}"
}
}
响应数据说明:
code: 错误代码msg: 错误代码含义,以人类可读的方式描述错误代码具体含义data: 对错误信息进一步描述ErrorMsg: 描述数据校验失败的报错信息,${ACTION_NAME}表示操作名称,${ACTION_RESULT}表示操作结果
2.3 打开 DevContainer
请求方式:
GET /api/devcontainer?_=${CurrentTimestamp}&repoId=${REPO_ID}&wait=${IS_WAITING}
| 请求参数 | 类型 | 含义 | 作用 |
|---|---|---|---|
_ |
整数 | 匿名参数,存放任意值(推荐使用当前的时间戳) | 用于防止 HTTP GET 请求被缓存,保证每次请求都能到达服务器端 |
repoId |
字符串 | 仓库 ID | 根据仓库打开关联的 DevContainer |
wait |
布尔 | 是否阻塞等待 DevContainer 就绪 | 是否注册监听器,在超时时间内阻塞等待 DevContainer 就绪 |
| 请求头 | 载荷 | 作用 |
|---|---|---|
Authorization |
token ${accessToken} |
登录凭证,用于标识用户身份,防止接口被滥用 |
Content-Type |
application/json |
用于标识返回数据格式是 JSON |
响应格式(操作成功):
{
"code": 0,
"msg": "操作成功",
"data": {
"devContainerId": 38,
"devContainerName": "daimingchen-12-dcbb9c5b8a0611ef9c1a4e1bce2a7080",
"devContainerHost": "devcontainer.devstar.cn",
"devContainerUsername": "root",
"devContainerWorkDir": "/data",
"repoId": 19,
"repoName": "12",
"repo_owner_name": "leviyanx",
"repo_link": "/leviyanx/12",
"devContainerPort": 30000
}
}
响应数据说明:
code: 错误代码,0表示无错误msg: 错误代码含义,以人类可读的方式描述错误代码的具体含义,0代表获取用户 DevContainer 连接信息成功data: 返回数据data字段名称类型 含义 devContainerId整数 DevContainer ID devContainerName字符串 唯一标识 DevContainer 名称 devContainerHost字符串 SSH 连接主机的 IP 或者 DNS 域名 devContainerPort整数 SSH 连接主机的端口号 devContainerUsername字符串 SSH 登录用户名 devContainerWorkDir字符串 SSH 登录成功后工作目录 repoId整数 DevContainer 关联的仓库的 ID repoName字符串 DevContainer 关联的仓库的名称 repo_owner_name字符串 DevContainer 关联的仓库的所有者用户 ID repo_link字符串 DevContainer 关联的仓库的访问绝对地址 URL repoDescription字符串 DevContainer 关联的仓库的描述信息(可选字段)
响应格式(操作失败:未登录):
{
"code": 1,
"msg": "未登录,禁止访问"
}
响应数据说明:
code: 错误代码msg: 错误代码含义,以人类可读的方式描述错误代码具体含义
响应格式(操作失败:无效参数):
{
"code": 11002,
"msg": "无效参数"
}
响应数据说明:
code: 错误代码msg: 错误代码含义,以人类可读的方式描述错误代码具体含义
响应格式(操作失败:发生内部错误,包括 DevContainer 未在超时时间内就绪):
{
"code": 11004,
"msg": "打开 DevContainer 失败",
"data": {
"ErrorMsg": "......"
}
}
响应数据说明:
code: 错误代码msg: 错误代码含义,以人类可读的方式描述错误代码具体含义data: 对错误信息进一步描述ErrorMsg: 描述数据校验失败的报错信息- 参数无效:Illegal Params
- DevContainer 未找到:DevContainer NOT found in repo '
${REPO_NAME}'(repoId =${REPO_ID}) of user '${USERNAME}'(userId =${USER_ID}) - 其他:Failed to
${ACTION_NAME}in DevContainer Service:${ACTION_RESULT}
补充: 如何判断 DevContainer 就绪状态
在 k8s 中,DevContainer 以 k8s CRD
DevcontainerApp资源定义,可参考如下 YAML:apiVersion: devcontainer.devstar.cn/v1 kind: DevcontainerApp metadata: name: studio-test namespace: devstar-studio-ns spec: statefulset: image: devstar.cn/public/base-ssh-devcontainer:ubuntu-20.04-20241014 gitRepositoryURL: https://gitee.com/daimingchen_gitee/mock-repo command: - /bin/bash - -c - service ssh restart && tail -f /dev/null containerPort: 22 sshPublicKeyList: - ssh-rsa AAA......e8 SSHPublicKey - ssh-rsa AAA......e9 YetAnotherSSHPublicKey使用
kubectl创建DevcontainerApp:kubectl apply -f devcontainerapp-demo.yaml等待一段时间后,获取 DevcontainerApp
studio-test的状态:kubectl get devcontainerapp -n devstar-studio-ns studio-test -o yaml即可得到下列 YAML
apiVersion: devcontainer.devstar.cn/v1 kind: DevcontainerApp metadata: name: studio-test namespace: devstar-studio-ns creationTimestamp: "2024-10-16T12:05:47Z" generation: 1 resourceVersion: "92973809" uid: 867c8bc6-1b79-4c41-8659-686b176f4c56 spec: statefulset: image: devstar.cn/public/base-ssh-devcontainer:ubuntu-20.04-20241014 gitRepositoryURL: https://gitee.com/daimingchen_gitee/mock-repo command: - /bin/bash - -c - service ssh restart && tail -f /dev/null containerPort: 22 sshPublicKeyList: - ssh-rsa AAA......e8 SSHPublicKey - ssh-rsa AAA......e9 YetAnotherSSHPublicKey status: nodePortAssigned: 30000 ready: true更详细地,
status.ready域具体赋值由下列两个指标判断:
- 分配的 NodePort 端口值
nodePortAssigned取值范围在左闭右闭区间[30000, 32767]- StatefulSet 控制下的 Pod 中的容器就绪探针探测成功
总之,在 DevStar Studio 中,只需要读取集群中 k8s CRD
DevcontainerApp的status.ready域即可判断 DevContainer 是否就绪
2.4 删除 DevContainer
请求方式:
DELETE /api/devcontainer?repoId=${REPO_ID}
| 请求参数 | 类型 | 含义 | 作用 |
|---|---|---|---|
repoId |
字符串 | 仓库 ID | 根据仓库打开关联的 DevContainer |
| 请求头 | 载荷 | 作用 |
|---|---|---|
Authorization |
token ${accessToken} |
登录凭证,用于标识用户身份,防止接口被滥用 |
Content-Type |
application/json |
用于标识返回数据格式是 JSON |
响应格式(操作成功):
{
"code": 0,
"msg": "操作成功"
}
响应格式(操作失败:未登录):
{
"code": 1,
"msg": "未登录,禁止访问"
}
响应格式(操作失败:未找到 DevContainer):
{
"code": 11005,
"msg": "删除 DevContainer 失败",
"data": {
"ErrorMsg": "Illegal Params: [opts.RepoId]"
}
}