add webterminal dockerfile

This commit is contained in:
init
2025-09-04 10:48:46 +08:00
repo.diff.parent 7f86efe563
repo.diff.commit 6686a44316
repo.diff.stats_desc%!(EXTRA int=10, int=201, int=13)

repo.diff.view_file

@@ -918,6 +918,7 @@ generate-manpage: ## generate manpage
.PHONY: devstar
devstar:
docker build -t devstar-studio:latest -f docker/Dockerfile.devstar .
docker build -t devstar.cn/devstar/webterminal:latest -f docker/Dockerfile.webTerminal .
.PHONY: docker
docker:

repo.diff.view_file

@@ -73,7 +73,7 @@ RUN chown git:git /var/lib/gitea /etc/gitea
COPY --from=build-env /tmp/local /
COPY --from=build-env --chown=root:root /go/src/code.gitea.io/gitea/gitea /app/gitea/gitea
COPY --from=build-env --chown=root:root /go/src/code.gitea.io/gitea/environment-to-ini /usr/local/bin/environment-to-ini
COPY --from=build-env --chown=root:root /go/src/code.gitea.io/gitea/webTerminal.sh /app/gitea/webTerminal.sh
# git:git
USER 1000:1000
ENV GITEA_WORK_DIR=/var/lib/gitea

repo.diff.view_file

@@ -0,0 +1,40 @@
FROM docker.io/library/ubuntu:24.04 AS build-env
RUN apt-get update && \
apt-get install -y \
git \
build-essential \
cmake \
libjson-c-dev \
libwebsockets-dev
RUN git clone https://devstar.cn/devstar/webTerminal.git /home/webTerminal
# 设置工作目录并构建
WORKDIR /home/webTerminal/build
RUN cmake ..
RUN make && make install
FROM ubuntu:24.04
# 从构建阶段复制编译好的程序
COPY --from=build-env /home/webTerminal/build/ttyd /home/webTerminal/build/ttyd
# 只安装运行时需要的库
RUN apt-get update && \
apt-get install -y \
curl && \
curl -fsSL https://mirrors.ustc.edu.cn/docker-ce/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc && \
apt-get install -y tini \
libjson-c-dev \
libwebsockets-dev && \
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://mirrors.ustc.edu.cn/docker-ce/linux/ubuntu/ \
$(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
tee /etc/apt/sources.list.d/docker.list > /dev/null && \
apt-get update && apt-get install -y docker-ce-cli && \
apt remove --purge curl -y && apt autoremove -y && apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
ENTRYPOINT ["/usr/bin/tini", "--"]
CMD ["/home/webTerminal/build/ttyd", "-W", "bash"]

repo.diff.view_file

@@ -8,8 +8,8 @@ import (
)
const (
// TplDevstarHome 显示 DevStar Home 页面 templates/devstar-home-vscode.tmpl
TplDevstarHome templates.TplName = "repo/devcontainer/devstar-home-vscode"
// TplDevstarHome 显示 DevStar Home 页面 templates/vscode-home.tmpl
TplDevstarHome templates.TplName = "repo/devcontainer/vscode-home"
)
// DevstarHome 渲染适配于 VSCode 插件的 DevStar Home 页面

repo.diff.view_file

@@ -1,12 +1,14 @@
package devcontainer
import (
"archive/tar"
"bytes"
"context"
"fmt"
"math"
"net"
"net/url"
"os"
"time"
"code.gitea.io/gitea/models/db"
@@ -19,6 +21,7 @@ import (
"code.gitea.io/gitea/modules/setting"
gitea_context "code.gitea.io/gitea/services/context"
files_service "code.gitea.io/gitea/services/repository/files"
"github.com/docker/docker/api/types"
"xorm.io/builder"
)
@@ -501,15 +504,62 @@ func GetTerminalCommand(ctx context.Context, userID string, repo *repo.Repositor
return "", "", err
}
if status == "running" {
//添加脚本文件
if setting.K8sConfig.Enable {
} else {
var scriptContent []byte
_, err = os.Stat("webTerminal.sh")
if os.IsNotExist(err) {
_, err = os.Stat("/app/gitea/webTerminal.sh")
if os.IsNotExist(err) {
return "", "", err
} else {
scriptContent, err = os.ReadFile("/app/gitea/webTerminal.sh")
if err != nil {
return "", "", err
}
}
} else {
scriptContent, err = os.ReadFile("webTerminal.sh")
if err != nil {
return "", "", err
}
}
// 创建 tar 归档文件
var buf bytes.Buffer
tw := tar.NewWriter(&buf)
defer tw.Close()
// 添加文件到 tar 归档
AddFileToTar(tw, "webTerminal.sh", string(scriptContent), 0777)
// 创建 Docker 客户端
cli, err := docker_module.CreateDockerClient(ctx)
if err != nil {
return "", "", err
}
// 获取容器 ID
containerID, err := docker_module.GetContainerID(cli, devContainerInfo.Name)
if err != nil {
return "", "", err
}
err = cli.CopyToContainer(ctx, containerID, "/home", bytes.NewReader(buf.Bytes()), types.CopyToContainerOptions{})
if err != nil {
log.Info("%v", err)
return "", "", err
}
}
realTimeStatus = 3
}
}
break
case 3:
//正在创建容器,创建容器成功,则状态转移
//正在初始化容器,初始化容器成功,则状态转移
if setting.K8sConfig.Enable {
//k8s的逻辑
} else {
status, err := CheckDirExistsFromDocker(ctx, devContainerInfo.Name, devContainerInfo.DevcontainerWorkDir)
if err != nil {
return "", "", err
@@ -520,7 +570,7 @@ func GetTerminalCommand(ctx context.Context, userID string, repo *repo.Repositor
}
break
case 4:
//正在创建容器,创建容器成功,则状态转移
//正在连接容器
if setting.K8sConfig.Enable {
//k8s的逻辑
} else {

repo.diff.view_file

@@ -1,6 +1,7 @@
package devcontainer
import (
"archive/tar"
"context"
"fmt"
"io"
@@ -210,3 +211,19 @@ func ReplacePortOfUrl(originalURL, targetPort string) (string, error) {
newURL := parsedURL.String()
return newURL, nil
}
// addFileToTar 将文件添加到 tar 归档
func AddFileToTar(tw *tar.Writer, filename string, content string, mode int64) error {
hdr := &tar.Header{
Name: filename,
Mode: mode,
Size: int64(len(content)),
}
if err := tw.WriteHeader(hdr); err != nil {
return err
}
if _, err := tw.Write([]byte(content)); err != nil {
return err
}
return nil
}

repo.diff.view_file

@@ -239,13 +239,23 @@ func CreateDevContainerByDockerCommand(ctx context.Context, newDevcontainer *dev
log.Info("Failed to insert record: %v", err)
return err
}
cfg, err := setting.NewConfigProviderFromFile(setting.CustomConf)
if err != nil {
return err
}
//创建并运行容器的命令
if _, err := dbEngine.Table("devcontainer_output").Insert(&devcontainer_models.DevcontainerOutput{
Output: "",
Status: "waitting",
UserId: newDevcontainer.UserId,
RepoId: newDevcontainer.RepoId,
Command: `docker -H ` + dockerSocket + ` run -d --name ` + newDevcontainer.Name + ` -p 22 ` + imageName + ` sh -c "tail -f /dev/null"` + "\n",
Output: "",
Status: "waitting",
UserId: newDevcontainer.UserId,
RepoId: newDevcontainer.RepoId,
Command: `docker -H ` + dockerSocket + ` run -d --name ` + newDevcontainer.Name +
` -p 22 ` +
` -e RepoLink="` + strings.TrimSuffix(cfg.Section("server").Key("ROOT_URL").Value(), `/`) + repo.Link() + `" ` +
` -e WorkSpace="` + newDevcontainer.DevcontainerWorkDir + `/` + repo.Name + `"` +
` -e PublicKeyList="` + strings.Join(publicKeyList, "\n") + `" ` +
imageName +
` sh -c "tail -f /dev/null"` + "\n",
ListId: 2,
DevcontainerId: newDevcontainer.Id,
}); err != nil {
@@ -258,7 +268,7 @@ func CreateDevContainerByDockerCommand(ctx context.Context, newDevcontainer *dev
Status: "waitting",
UserId: newDevcontainer.UserId,
RepoId: newDevcontainer.RepoId,
Command: `docker -H ` + dockerSocket + ` exec ` + newDevcontainer.Name + ` sh -c "echo \"` + newDevcontainer.DevcontainerHost + ` host.docker.internal\" | tee -a /etc/hosts;apt update;apt install -y git ;git clone ` + strings.TrimSuffix(setting.AppURL, "/") + repo.Link() + " /data/workspace/" + repo.Name + `; apt install -y ssh;echo -e "PubkeyAuthentication yes\nPermitRootLogin yes\n" | tee -a /etc/ssh/sshd_config;rm -f /etc/ssh/ssh_host_*; ssh-keygen -A; service ssh restart;mkdir -p ~/.ssh;chmod 700 ~/.ssh;echo "` + strings.Join(publicKeyList, "\n") + `" > ~/.ssh/authorized_keys;chmod 600 ~/.ssh/authorized_keys"` + "\n",
Command: `docker -H ` + dockerSocket + ` exec ` + newDevcontainer.Name + ` /home/webTerminal.sh start` + "\n",
ListId: 3,
DevcontainerId: newDevcontainer.Id,
}); err != nil {
@@ -552,7 +562,7 @@ func RegistWebTerminal(ctx context.Context) error {
containerName := "webterminal-" + timestamp
//创建并启动WebTerminal容器
err = docker_module.CreateAndStartContainer(ctx, cli, setting.DevContainerConfig.Web_Terminal_Image,
[]string{"sh", "-c", "/home/webTerminal/build/ttyd -W bash\n"},
nil,
nil, binds,
nat.PortSet{
"7681/tcp": struct{}{},

repo.diff.view_file

@@ -431,4 +431,4 @@
</html>
<!-- footer end -->
{{template "repo/devcontainer/devstar-home-vscode-js" .}}
{{template "repo/devcontainer/vscode-home-js" .}}

70
webTerminal.sh Normal file
repo.diff.view_file

@@ -0,0 +1,70 @@
#!/bin/bash
# 获取参数
ACTION=$1
OS_ID=$(grep '^ID=' /etc/os-release | cut -d= -f2 | tr -d '"')
# 根据参数执行不同命令
case $ACTION in
"start")
echo "Starting service..."
# 启动服务的命令
echo "newDevcontainer.DevcontainerHost host.docker.internal" | tee -a /etc/hosts;
case $OS_ID in
ubuntu|debian)
apt-get update -y
apt-get install ssh git -y
;;
centos)
# sudo yum update -y
# sudo yum install -y epel-release
# sudo yum groupinstall -y "Development Tools"
# sudo yum install -y yaml-cpp yaml-cpp-devel
;;
fedora)
# sudo dnf update -y
# sudo dnf group install -y "Development Tools"
# sudo dnf install -y yaml-cpp yaml-cpp-devel
;;
*)
failure "Unsupported OS: $OS_ID"
exit 1
;;
esac
echo -e "PubkeyAuthentication yes\nPermitRootLogin yes\n" | tee -a /etc/ssh/sshd_config;
rm -f /etc/ssh/ssh_host_*;
ssh-keygen -A;
mkdir -p ~/.ssh;
chmod 700 ~/.ssh;
case $OS_ID in
ubuntu|debian)
service ssh restart;
;;
centos)
;;
fedora)
;;
*)
failure "Unsupported OS: $OS_ID"
exit 1
;;
esac
echo "$PublicKeyList" > ~/.ssh/authorized_keys;
chmod 600 ~/.ssh/authorized_keys
git clone $RepoLink $WorkSpace
;;
"stop")
echo "Stopping service..."
# 停止服务的命令
;;
"restart")
echo "Restarting service..."
# 重启服务的命令
;;
*)
echo "Usage: $0 {start|stop|restart}"
exit 1
;;
esac