# cloudtty
**Repository Path**: hao_biao/cloudtty
## Basic Information
- **Project Name**: cloudtty
- **Description**: A Friendly Kubernetes CloudShell (Web Terminal) !
- **Primary Language**: Unknown
- **License**: MIT
- **Default Branch**: main
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 0
- **Created**: 2026-01-13
- **Last Updated**: 2026-01-13
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# CloudTTY:一款专用于 Kubernetes 的 Cloud Shell Operator
简体中文 | [English](https://github.com/cloudtty/cloudtty/blob/main/README.md)
CloudTTY 是专为 Kubernetes 云原生环境打造的 Web 终端和 Cloud Shell Operator。
通过 CloudTTY,您可以轻松用浏览器打开一个终端窗口,操控多云资源。
CloudTTY 意指云原生虚拟控制台,也称为 Cloud Shell(云壳)。
想象一下,在复杂多变的多云环境中,嵌入这样一层 Shell 来操纵整个云资源。
而这就是 CloudTTY 的设计初衷,我们希望在日趋复杂的 Kubernetes 容器云环境中,能够为开发者提供一个简单的 Shell 入口。
> TTY 全称为 TeleTYpe,即电传打字机、电报机。
> 没错,就是那种很古老会发出滴滴答答声响、用线缆相连的有线电报机,那是一种只负责显示和打字的纯 IO 设备。
> 近些年随着虚拟化技术的飞速发展,TTY 常指虚拟控制台或虚拟终端。
**CloudTTY 是一个[云原生计算基金会 (CNCF)](https://cncf.io/) 全景图项目。**
## 为什么需要 CloudTTY?
目前,社区的 [ttyd](https://github.com/tsl0922/ttyd) 等项目对 TTY 技术的探索已经达到了一定的深度,可以提供浏览器之上的终端能力。
但是在 Kubernetes 的场景下,这些 TTY 项目还需要更加云原生的能力拓展。
如何让 ttyd 在容器内运行,如何通过 NodePort\Ingress 等方式访问,如何用 CRD 的方式创建多个实例?
恭喜你,CloudTTY 提供了这些问题的解决方案,欢迎试用 CloudTTY 🎉!
## 适用场景
CloudTTY 适用于以下几个场景。
1. 如果企业正使用容器云平台来管理 Kubernetes,但由于安全原因,无法随意 SSH 到主机上执行 kubectl 命令,这就需要一种 Cloud Shell 能力。
2. 在浏览器网页上进入运行中的容器(`kubectl exec`)的场景。
3. 在浏览器网页上能够滚动展示容器日志的场景。
CloudTTY 的网页终端使用效果如下:

如果将 CloudTTY 集成到您自己的 UI 里面,最终效果 demo 如下:

## 快速入门步骤
CloudTTY 的入门比较简单,请参照以下步骤进行安装和使用。
1. 安装并等待 Pod 运行起来。
```shell
helm repo add cloudtty https://cloudtty.github.io/cloudtty
helm repo update
helm install cloudtty-operator --version 0.5.0 cloudtty/cloudtty
kubectl wait deployment cloudtty-operator-controller-manager --for=condition=Available=True
```
2. 创建 CR,启动 cloudtty 的实例,并观察其状态。
```shell
kubectl apply -f https://raw.githubusercontent.com/cloudtty/cloudtty/v0.5.0/config/samples/local_cluster_v1alpha1_cloudshell.yaml
```
更多范例,参见 [config/samples/](./config/samples/)。
3. 观察 CR 状态,获取访问接入点:
```shell
kubectl get cloudshell -w
```
输出类似于:
```console
NAME USER COMMAND TYPE URL PHASE AGE
cloudshell-sample root bash NodePort 192.168.4.1:30167 Ready 31s
cloudshell-sample2 root bash NodePort 192.168.4.1:30385 Ready 9s
```
当 cloudshell 对象状态变为 `Ready`,并且 `URL` 字段出现之后,就可以通过该字段的访问方式,在浏览器打开:

### 怎么构建自定义镜像
大多数用户除了使用基本的 `kubectl` 工具来管理集群外,还需要更多丰富的工具来管理集群。可以基于 cloudshell 的基础镜像来自定义,下面是一个添加 `karmadactl` 工具的一个案例:
* 修改 [Dockerfile.example](https://github.com/cloudtty/cloudtty/blob/main/docker/Dockerfile.example) 文件。
```shell
FROM ghcr.io/cloudtty/cloudshell:v0.6.0
RUN curl -fsSLO https://github.com/karmada-io/karmada/releases/download/v1.2.0/kubectl-karmada-linux-amd64.tgz \
&& tar -zxf kubectl-karmada-linux-amd64.tgz \
&& chmod +x kubectl-karmada \
&& mv kubectl-karmada /usr/local/bin/kubectl-karmada \
&& which kubectl-karmada
ENTRYPOINT ttyd
```
* 重新构建带有 karmadactl 工具的新镜像:
```shell
docker build -t . -f docker/Dockerfile-webtty
```
### 使用自定义的 cloudshell 镜像
我们有两种方式来设置 cloudshell 的自定义镜像:
1. 直接通过 cloudshell CR 字段 `spec.image` 来设置。
```yaml
apiVersion: cloudshell.cloudtty.io/v1alpha1
kind: CloudShell
metadata:
name: cloudshell-sample
spec:
secretRef:
name: "my-kubeconfig"
image: ghcr.io/cloudtty/customize_cloudshell:latest
```
2. 在安装 CloudTTY 时可以设置 `JobTemplate` 镜像参数来运行自己的 cloudshell 的镜像。
```shell
helm install cloudtty-operator --version 0.5.0 cloudtty/cloudtty --set jobTemplate.image.registry= --set jobTemplate.image.repository= --set jobTemplate.image.tag=
```
> 如果你已经安装了 CloudTTY,还可以修改 `JobTemplate` 的 ConfigMap 来设置 cloudshell 的镜像。
## 进阶用法
### 进阶 1:用 CloudTTY 访问其他集群
如果是本地集群,可以不提供 kubeconfig,CloudTTY 会创建具有 `cluster-admin` 角色权限的 `serviceaccount`。
在容器的内部,`kubectl` 会自动发现 `ca` 证书和 token。如果有安全方面的考虑,您也可以自己提供 kubeconfig 来控制不同用户的权限。
如果是远端集群,CloudTTY 可以执行 kubectl 命令行工具。若访问集群,需要指定 kubeconfig。
用户需自己提供 kubeconfig 并储存在 Secret 中,并且在 `cloudshell` 的 CR 中,通过 `spec.secretRef.name` 指定 Secret 的名称。
CloudTTY 会自动挂载到容器中,请确保服务器地址与集群网络连接顺畅。
设置 kubeconfig 的步骤:准备 `kube.conf`,放入 Secret 中,并确保密钥/证书是 base64 而不是本地文件。
```shell
kubectl create secret generic my-kubeconfig --from-file=kube.config
```
### 进阶 2:用 CloudTTY 访问集群上的 node 主机
可以在 cloudshell 的基础镜像中集成 [kubectl-node-shell](https://github.com/kvaps/kubectl-node-shell) 插件,使用该插件可以通过 `kubectl` 的命令登录到集群中任意节点上。该命令将会在节点上启动一个具有特权 Pod。如果对安全性要求非常高,请谨慎使用此功能。
* 修改 [Dockerfile.example](https://github.com/cloudtty/cloudtty/blob/main/docker/Dockerfile.example) 文件。
```shell
FROM ghcr.io/cloudtty/cloudshell:v0.6.0
RUN curl -fsSLO https://github.com/kvaps/kubectl-node-shell/raw/master/kubectl-node_shell \
&& chmod +x ./kubectl-node_shell \
&& mv ./kubectl-node_shell /usr/local/bin/kubectl-node_shell \
&& which kubectl-node_shell
ENTRYPOINT ttyd
```
* 重新构建带有 node-shell 工具的新镜像:
```shell
docker build -t . -f docker/Dockerfile.example
```
下面是一个使用的实例:
```yaml
apiVersion: cloudshell.cloudtty.io/v1alpha1
kind: CloudShell
metadata:
name: cloudshell-node-shell
spec:
configmapName: ""
commandAction: "kubectl node-shell "
```
更多的示例可以参考 [kubectl-node-shell](https://github.com/kvaps/kubectl-node-shell)。
> 集群中如果已经存在 `PodSecurity` 和 `PSP` 等安全性策略,可能会影响该功能的使用。
### 进阶 3:修改服务暴露方式
CloudTTY 提供了以下 4 种服务暴露模式以满足不同的使用场景:
* `ClusterIP`:在集群中创建 ClusterIP 类型的 [Service](https://kubernetes.io/zh-cn/docs/concepts/services-networking/service/) 资源。
适用于第三方集成 CloudTTY 服务,用户可以选择更加灵活的方式来暴露自己的服务。
* `NodePort`:这是默认的模式,也是最简单的暴露服务模式。
在集群中创建 NodePort 类型的 Service 资源,通过节点 IP 和对应的端口号访问 CloudTTY 服务。
* `Ingress`:在集群中创建 ClusterIP 类型的 Service 资源,并创建 Ingress 资源,通过路由规则负载到 Service 上。
适合在集群中使用 [Ingress Controller](https://kubernetes.io/zh-cn/docs/concepts/services-networking/ingress-controllers/) 进行流量负载的情况。
* `VirtualService (istio)`:在集群中创建 ClusterIP 类型的 Service 资源,并创建 VirtaulService 资源。
适合在集群中使用 [Istio](https://github.com/istio/istio) 进行流量负载的情况。
### featureGate
AllowSecretStoreKubeconfig:使用 secret 的方式存储 kubeconfig 文件,如果开启此 featureGate,该字段 `spec.configmapName` 将会失效,使用 `spec.secretRef.name` 来设置 kubeconfig, 目前处于 alpha 阶段,默认是关闭。
#### 如何开启 featrueGate
1. 如果使用 yaml 方式部署 CloudTTY,在 operator 的启动参数中添加 `--feature-gates=AllowSecretStoreKubeconfig=true`.
2. 如果使用 helm 部署的情况,安装指定参数 `--set image.featureGates.AllowSecretStoreKubeconfig=true`.
### 工作原理
CloudTTY 的工作原理如下:
1. Operator 会在对应的命名空间(Namespace)下创建同名的 `job` 和 `service`。
如果使用 Ingress 或者 VirtualService 模式,还会创建对应的路由信息。
2. 当 Pod 运行状态为 `Ready` 之后,就将访问点写入 cloudshell 的 status 里。
3. 当 [Job](https://kubernetes.io/zh-cn/docs/concepts/workloads/controllers/job/) 在 TTL 之后或者因其他原因结束之后,
一旦 Job 状态变为 `Completed`,cloudshell 的状态也会变为 `Completed`。
我们可以设置当 cloudshell 的状态为 `Completed` 时,同时删除相关联的资源。
4. 当 cloudshell 被删除时,会自动删除对应的 Job 和 Service (通过 `ownerReference`)。
如果使用 Ingress 或者 VirtualService 模式时,还会删除对应的路由信息。
## 开发者模式
CloudTTY 还提供了开发者模式。
1. 运行 Operator 并安装 CRD。由开发者进行编译执行(建议普通用户使用上述 [Helm 安装](#快速上手))。
1. 安装 CRD
- (Option 1)从 YAML:先 `make generate-yaml`,然后 apply 生成的 yaml
- (Option 2)从代码:克隆代码之后运行 `make install`
2. 运行 Operator:`make run`
2. 创建 CR。比如开启窗口后自动打印某个容器的日志:
```yaml
apiVersion: cloudshell.cloudtty.io/v1alpha1
kind: CloudShell
metadata:
name: cloudshell-sample
spec:
secretRef:
name: "my-kubeconfig"
runAsUser: "root"
commandAction: "kubectl -n kube-system logs -f kube-apiserver-cn-stack"
once: false
```
### 开发指南
基于 kubebuilder 框架开发;以 ttyd 为基础构建镜像。
1. 初始化框架,初始化 kubebuilder 项目。
```shell
kubebuilder init --domain daocloud.io --repo daocloud.io/cloudshell
kubebuilder create api --group cloudshell --version v1alpha1 --kind CloudShell
```
2. 生成 manifest。
```shell
make manifests
```
3. 调试(使用默认的 kube.conf)。
```shell
make install # 在目标集群安装 CRD
make run # 启动 Operator 的代码
```
4. 构建镜像。
```shell
make docker-build
make docker-push
```
5. 生成 Operator 部署的 yaml。使用 kustomize 渲染 CRD yaml。
```shell
make generate-yaml
```
6. 构建 helm 包。
```shell
make build-chart
```
> 开发注意事项:
>
> go get 的 gotty 暂不能用,需要下载:
>
> ```
> wget https://github.com/yudai/gotty/releases/download/v1.0.1/gotty_linux_amd64.tar.gz
> ```
### Docker 镜像和用 Docker 做简化实验
镜像在 master 分支的 docker/目录下,具体操作步骤如下:
1. 创建 ConfigMap 或 kube.conf
```shell
kubectl create configmap my-kubeconfig --from-file=/root/.kube/config
```
2. 根据不同场景操作:
* 日常 kubectl 的 console。
```bash
bash run.sh
```
* 实时查看 Event。
```bash
bash run.sh "kubectl get event -A -w"
```
* 实时查看 Pod 日志。
```bash
NS=caas-system
POD=caas-api-6d67bfd9b7-fpvdm
bash run.sh "kubectl -n $NS logs -f $POD"
```
## 特别鸣谢
CloudTTY 这个项目的很多技术实现基于 [ttyd](https://github.com/tsl0922/ttyd),非常感谢 `tsl0922`、`yudai` 和社区开发者们的努力.
CloudTTY 前端 UI 及其镜像内所用的二进制文件均源于 ttyd 社区。
## 交流和探讨
如果您有任何疑问,请联系我们:
* [Slack 频道](https://cloud-native.slack.com/archives/C03LA6AUF7V)
* 微信交流群:请联系 `calvin0327`(wen.chen@daocloud.io) 加入交流群
非常欢迎大家[提出 issue](https://github.com/cloudtty/cloudtty/issues) 和[发起 PR](https://github.com/cloudtty/cloudtty/pulls)。🎉🎉🎉
## 下一步
CloudTTY 还将提供更多的功能,此处列出一些已经排上日程的开发计划。
1. 通过 RBAC 生成的 `/var/run/secret` 进行权限控制
2. 代码还未做边界处理(如 NodePort 准备工作)
3. 为了安全,Job 应该在单独的 Namespace 跑,而不是在 CR 中用同一个 Namespace
4. 需要检查 Pod 的 Running 和 endpoint 的 Ready,才能置 CR 为 Ready
5. 目前 TTL 只反映到 shell 的 timeout,没有反映到 Job 的 yaml 里
6. Job 的创建模板目前是 hardcode 方式,应该提供更灵活的方式修改 Job 的模板
## 贡献者
Made with [contrib.rocks](https://contrib.rocks).
cloudtty 位列 CNCF 云原生全景图。