Compare commits

...

3 Commits

Author SHA1 Message Date
wang b7ac6612be ok 2024-07-02 13:02:37 +08:00
wang df8ece4dd8 Merge remote-tracking branch 'origin/master'
# Conflicts:
#	app-dm/src/router/index.jsx
#	python/app.py
#	python/k8s_func.py
2024-07-02 13:02:19 +08:00
wang ce75c0484d 容器部署创建回收 2024-07-02 13:00:00 +08:00
86 changed files with 553 additions and 142 deletions

View File

@ -4,31 +4,12 @@ import React, { useEffect, useState, useRef } from 'react';
import { useLocation } from 'react-router-dom'; import { useLocation } from 'react-router-dom';
import io, { Socket } from "socket.io-client"; import io, { Socket } from "socket.io-client";
function base64Decode(encoded: string): string {
return atob(encoded);
}
export default function WebSSH() { export default function WebSSH({ ip = "10.233.183.99", port = "22", password = "123456", user = "dmdba" }) {
const location = useLocation(); const location = useLocation();
const terminalObj = useRef<HTMLDivElement | null>(null); const terminalObj = useRef<HTMLDivElement | null>(null);
const [terminal, setTerminal] = useState<Terminal | null>(null); const [terminal, setTerminal] = useState<Terminal | null>(null);
const [socket, setSocket] = useState<Socket | null>(null); const [socket, setSocket] = useState<Socket | null>(null);
const [ip, setIp] = useState("");
const [port, setPort] = useState("");
const [password, setPassword] = useState("");
useEffect(() => {
const params = new URLSearchParams(location.search);
const encodedIp = params.get("ip");
const encodedPort = params.get("port");
const encodedPassword = params.get("password");
if (encodedIp && encodedPort && encodedPassword) {
setIp(base64Decode(encodedIp));
setPort(base64Decode(encodedPort));
setPassword(base64Decode(encodedPassword));
}
}, [location]);
useEffect(() => { useEffect(() => {
if (terminal === null) { if (terminal === null) {
@ -69,9 +50,9 @@ export default function WebSSH() {
useEffect(() => { useEffect(() => {
if (socket && ip && port && password) { if (socket && ip && port && password) {
socket.emit("connect_ssh", { ip, port, password }); socket.emit("connect_ssh", { ip, port, password, user });
} }
}, [socket, ip, port, password]); }, [socket, ip, port, password, user]);
function pasteContent(event: React.MouseEvent) { function pasteContent(event: React.MouseEvent) {
navigator.clipboard.readText().then((content) => { navigator.clipboard.readText().then((content) => {

View File

@ -83,7 +83,7 @@ function SendTrain(){
endDate endDate
}) })
alert('发布成功') alert('发布成功')
window.location.href='http://localhost:3000/teacher/trainmanage' window.location.href='/teacher/trainmanage'
}catch{ }catch{
alert('SendTrainTest出错') alert('SendTrainTest出错')

View File

@ -11,11 +11,23 @@ import { max, min } from 'lodash';
// //
function Home(){ function Home(){
const student_ID=localStorage.getItem('islogin') const [isChecked,setisChecked]=useState(false)
if(student_ID==null){ //
window.location.href='http://localhost:3000/signin' // useEffect(()=>{
alert('未登录,请先前往登录') // if (!isChecked){
} // const is_login=localStorage.getItem('islogin')
// if(!is_login){
// alert('')
// window.location.href='/signin'
// }else{
// console.log(is_login);
// console.log('');
// setisChecked(true)
// }
// //login
// }
// },[]);//
// //
const [lesson, setLesson] = useState([]); const [lesson, setLesson] = useState([]);
const [firstlesson, setfirstlesson] = useState([]); const [firstlesson, setfirstlesson] = useState([]);
@ -36,7 +48,7 @@ function Home(){
setLesson(lesson_data) setLesson(lesson_data)
}catch(error){ }catch(error){
if(student_ID.length===6){ if(student_ID.length===6){
window.location.href='http://localhost:3000/teacher' window.location.href='/teacher'
return return
}else{ }else{
alert('提示出错') alert('提示出错')

View File

@ -81,7 +81,7 @@ function Exam() {
clearInterval(interval); clearInterval(interval);
alert('考试时间到!'); alert('考试时间到!');
correct() correct()
window.location.href='http://localhost:3000/subject' window.location.href='/subject'
} }
}, 1000); }, 1000);
return () => clearInterval(interval); return () => clearInterval(interval);
@ -183,7 +183,7 @@ function Exam() {
setCountdown(0) setCountdown(0)
localStorage.removeItem('time') localStorage.removeItem('time')
alert('提交成功') alert('提交成功')
window.location.href='http://localhost:3000/subject' window.location.href='/subject'
} }

View File

@ -154,7 +154,7 @@ function Operation2() {
localStorage.removeItem('answeredJudge') localStorage.removeItem('answeredJudge')
localStorage.removeItem('RemainingTime') localStorage.removeItem('RemainingTime')
alert('提交成功') alert('提交成功')
window.location.href='http://localhost:3000/train' window.location.href='/train'
localStorage.removeItem('TrainData') localStorage.removeItem('TrainData')
} }

4
app-dm/src/router/index.jsx Executable file → Normal file
View File

@ -23,7 +23,10 @@ import ClassID from '../TeacherPages/classlistpages/classId';
import ManageTest from '../TeacherPages/TestManage/ManageTest'; import ManageTest from '../TeacherPages/TestManage/ManageTest';
import SendTest from '../TeacherPages/TestManage/SendTest'; import SendTest from '../TeacherPages/TestManage/SendTest';
import Marking from '../TeacherPages/MarkingPages/Marking'; import Marking from '../TeacherPages/MarkingPages/Marking';
import SendTrain from '../TeacherPages/Trainmanage/SendTrain'
import TrainManage from '../TeacherPages/Trainmanage/Trainmanage'
import StudentLink from '../TeacherPages/MarkingPages/StudentLink'; import StudentLink from '../TeacherPages/MarkingPages/StudentLink';
import Test from '../TeacherPages/TestManage/Test.tsx'
import SendTrain from '../TeacherPages/Trainmanage/SendTrain'; import SendTrain from '../TeacherPages/Trainmanage/SendTrain';
@ -69,6 +72,7 @@ function App() {
<Route path="/classID/:key" element={<MainLayout headerNav={HeaderNavTeacher} />}> <Route path="/classID/:key" element={<MainLayout headerNav={HeaderNavTeacher} />}>
<Route index element={<ClassID/>} /> <Route index element={<ClassID/>} />
</Route> </Route>
<Route path="test" element={<Test />}/>
{/* 页面使用单独的布局不包含HeaderNav和HeaderNavTeacher */} {/* 页面使用单独的布局不包含HeaderNav和HeaderNavTeacher */}
<Route path="exam/:examId" element={<Exam />} />{/* 练习-考试页面 */} <Route path="exam/:examId" element={<Exam />} />{/* 练习-考试页面 */}

View File

@ -43,9 +43,11 @@ main() {
build_image build-dmpython build_image build-dmpython
build_image build-frontend build_image build-frontend
build_image flask-app build_image flask-app
build_image code-server
push_image flask-app push_image flask-app
push_image base-dm push_image base-dm
push_image code-server
echo "脚本结束" echo "脚本结束"
} }

View File

@ -31,3 +31,14 @@ services:
- '8765:8765' - '8765:8765'
command: gunicorn -w 3 -t 60 -b 0.0.0.0:8000 app:app command: gunicorn -w 3 -t 60 -b 0.0.0.0:8000 app:app
code-server:
build: ./docker/code-server
restart: always
image: code-server
depends_on:
- build-dmpython
ports:
- '8443:8443'
- '5000:5000'
- '3000:3000'

View File

@ -1,16 +1,24 @@
# base-dm
FROM base FROM base
# 添加用户 # 添加用户
RUN useradd -m -s /bin/bash dmdba \ RUN useradd -m -s /bin/bash dmdba \
# 修改用户密码 # 修改用户密码
&& echo "dmdba:123456" | chpasswd && echo "dmdba:123456" | chpasswd \
&& apt-get -y update \
&& apt-get install -y --no-install-recommends \
p7zip-full unzip wget \
&& apt-get clean \
&& rm -rf /config/* /tmp/* /var/lib/apt/lists/* /var/tmp/*
WORKDIR /home/dmdba WORKDIR /home/dmdba
# 传入安装包并解压 # 下载安装包并解压
RUN wget https://download.dameng.com/eco/adapter/DM8/202405/dm8_20240408_x86_rh7_64_ent_8.1.3.140.zip \ RUN wget https://download.dameng.com/eco/adapter/DM8/202405/dm8_20240408_x86_rh7_64_ent_8.1.3.140.zip --no-check-certificate \
&& unzip dm8_20240408_x86_rh7_64_ent_8.1.3.140.zip \ && unzip dm8_20240408_x86_rh7_64_ent_8.1.3.140.zip \
&& chown -R dmdba:dmdba /home/dmdba \ && chown -R dmdba:dmdba /home/dmdba \
&& rm -f dm8_20240408_x86_rh7_64_ent_8.1.3.140.zip \ && rm -f dm8_20240408_x86_rh7_64_ent_8.1.3.140.zip \
&& 7z x dm8_20240408_x86_rh7_64.iso \ && 7z x dm8_20240408_x86_rh7_64.iso \
&& rm -f dm8_20240408_x86_rh7_64.iso \ && rm -f dm8_20240408_x86_rh7_64.iso \
&& chmod +x DMInstall.bin && chmod +x DMInstall.bin \
&& apt-get remove -y p7zip-full unzip wget
USER dmdba USER dmdba
CMD ["/bin/bash", "-e"]

View File

@ -1,4 +1,5 @@
FROM ubuntu # base
FROM ubuntu:22.04
# apt安装时防止卡死在交互界面 # apt安装时防止卡死在交互界面
ENV DEBIAN_FRONTEND=noninteractive ENV DEBIAN_FRONTEND=noninteractive
ENV LANG=zh_CN.UTF-8 ENV LANG=zh_CN.UTF-8
@ -6,19 +7,14 @@ ENV LC_ALL=zh_CN.UTF-8
# 基础软件安装 # 基础软件安装
RUN sed -i 's@//.*archive.ubuntu.com@//mirrors.ustc.edu.cn@g' /etc/apt/sources.list \ RUN sed -i 's@//.*archive.ubuntu.com@//mirrors.ustc.edu.cn@g' /etc/apt/sources.list \
&& apt-get -y update && apt-get -y upgrade \ && apt-get -y update && apt-get -y upgrade \
&& apt-get install -y python3.10-venv libssl-dev sudo vim python3-pip ssh wget unzip p7zip* language-pack-zh-hans language-selector-common locales locales-all \ && apt-get install -y --no-install-recommends \
# 设置中文环境 # && apt-get install -y python3.10-venv libssl-dev sudo vim python3-pip ssh wget unzip p7zip* language-pack-zh-hans language-selector-common locales locales-all \
&& apt install -y $(check-language-support) \ ssh locales language-pack-zh-hans-base \
&& sed -i 's/^#PermitRootLogin prohibit-password/PermitRootLogin yes/' /etc/ssh/sshd_config \ && sed -i 's/^#PermitRootLogin prohibit-password/PermitRootLogin yes/' /etc/ssh/sshd_config \
&& sudo sed -i 's/^UsePAM yes/UsePAM no/' /etc/ssh/sshd_config \ && sed -i 's/^UsePAM yes/UsePAM no/' /etc/ssh/sshd_config \
&& echo "zh_CN.UTF-8 UTF-8" >> /etc/locale.gen \ && echo "zh_CN.UTF-8 UTF-8" >> /etc/locale.gen \
&& sudo /usr/sbin/update-locale LANG=zh_CN.UTF-8 LC_ALL=zh_CN.UTF-8 \ && /usr/sbin/update-locale LANG=zh_CN.UTF-8 LC_ALL=zh_CN.UTF-8 \
&& locale-gen \ && locale-gen \
&& pip config set global.index-url https://mirrors.bfsu.edu.cn/pypi/web/simple \ # && pip config set global.index-url https://mirrors.bfsu.edu.cn/pypi/web/simple \
&& echo "**** clean up ****" && \ && apt-get clean \
apt-get clean && \ && rm -rf /config/* /tmp/* /var/lib/apt/lists/* /var/tmp/*
rm -rf \
/config/* \
/tmp/* \
/var/lib/apt/lists/* \
/var/tmp/*

View File

@ -1,7 +1,24 @@
#build-dmpython
FROM base-dm FROM base-dm
WORKDIR /home/dmdba WORKDIR /home/dmdba
COPY auto_install.xml . COPY auto_install.xml .
RUN ./DMInstall.bin -q /home/dmdba/auto_install.xml RUN ./DMInstall.bin -q /home/dmdba/auto_install.xml \
&& rm -rf ./DMInstall.bin
USER root
RUN apt-get -y update \
&& apt-get install -y --no-install-recommends \
python3-dev python3-pip gcc \
&& apt-get clean \
&& rm -rf /config/* /tmp/* /var/lib/apt/lists/* /var/tmp/* \
&& pip3 install wheel
USER dmdba
# 编译 # 编译
WORKDIR /home/dmdba/dmdbms/drivers/python/dmPython WORKDIR /home/dmdba/dmdbms/drivers/python/dmPython
RUN DM_HOME=/home/dmdba/dmdbms python3 setup.py bdist_wheel && mkdir /home/dmdba/build_artifacts && cp dist/dmPython-2.5.5-cp310-cp310-linux_x86_64.whl /home/dmdba/build_artifacts/ && cp /home/dmdba/dmdbms/bin/libdmdpi.so /home/dmdba/build_artifacts/ RUN DM_HOME=/home/dmdba/dmdbms python3 setup.py bdist_wheel \
&& mkdir /home/dmdba/build_artifacts \
&& mv dist/dmPython-2.5.5-cp310-cp310-linux_x86_64.whl /home/dmdba/build_artifacts/ \
&& cp /home/dmdba/dmdbms/bin/libdmdpi.so /home/dmdba/build_artifacts/
USER root
RUN apt-get remove -y python3-dev python3-pip gcc
USER dmdba

View File

@ -10,7 +10,7 @@
<KEY></KEY> <KEY></KEY>
<!--安装程序组件类型取值范围0、1、20 表示安装全部1 表示安装服务器2 表示安装客户端。缺省为0。 --> <!--安装程序组件类型取值范围0、1、20 表示安装全部1 表示安装服务器2 表示安装客户端。缺省为0。 -->
<INSTALL_TYPE>0</INSTALL_TYPE> <INSTALL_TYPE>1</INSTALL_TYPE>
<!--安装路径,不允许为空。 --> <!--安装路径,不允许为空。 -->
<INSTALL_PATH>/home/dmdba/dmdbms</INSTALL_PATH> <INSTALL_PATH>/home/dmdba/dmdbms</INSTALL_PATH>

View File

@ -1,57 +1,73 @@
FROM ghcr.io/linuxserver/baseimage-ubuntu:jammy #code-server
FROM build-dmpython
# set version label ENV DEBIAN_FRONTEND="noninteractive"
ARG BUILD_DATE WORKDIR /home/dmdba
ARG VERSION USER root
ARG CODE_RELEASE
LABEL build_version="Linuxserver.io version:- ${VERSION} Build-date:- ${BUILD_DATE}"
LABEL maintainer="aptalca"
# environment settings RUN apt-get update && apt-get install -y --no-install-recommends \
ARG DEBIAN_FRONTEND="noninteractive" git jq libatomic1 nano net-tools netcat python3-pip nodejs npm curl sudo catatonit \
ENV HOME="/config" cron \
curl \
RUN \ gnupg \
echo "**** install runtime dependencies ****" && \
apt-get update && \
apt-get install -y \
git \
jq \ jq \
libatomic1 \
nano \
net-tools \
netcat \ netcat \
# 安装python nodejs tzdata \
python3 \ xz-utils \
python3-pip \ && CODE_RELEASE=$(curl -sX GET https://api.github.com/repos/coder/code-server/releases/latest | awk '/tag_name/{print $4;exit}' FS='[""]' | sed 's|^v||') \
nodejs \ && mkdir -p /app/code-server \
npm \ && curl -o /tmp/code-server.tar.gz -L "https://github.com/coder/code-server/releases/download/v${CODE_RELEASE}/code-server-${CODE_RELEASE}-linux-amd64.tar.gz" \
sudo && \ && tar xf /tmp/code-server.tar.gz -C /app/code-server --strip-components=1 \
echo "**** install code-server ****" && \ && apt-get clean \
if [ -z ${CODE_RELEASE+x} ]; then \ && rm -rf /tmp/* /var/lib/apt/lists/* /var/tmp/* \
CODE_RELEASE=$(curl -sX GET https://api.github.com/repos/coder/code-server/releases/latest \ && pip3 install /home/dmdba/build_artifacts/dmPython-2.5.5-cp310-cp310-linux_x86_64.whl \
| awk '/tag_name/{print $4;exit}' FS='[""]' | sed 's|^v||'); \ && rm /home/dmdba/build_artifacts/dmPython-2.5.5-cp310-cp310-linux_x86_64.whl
fi && \
mkdir -p /app/code-server && \ # set environment variables
curl -o \ ENV HOME="/root" \
/tmp/code-server.tar.gz -L \ LANGUAGE="en_US.UTF-8" \
"https://github.com/coder/code-server/releases/download/v${CODE_RELEASE}/code-server-${CODE_RELEASE}-linux-amd64.tar.gz" && \ LANG="en_US.UTF-8" \
tar xf /tmp/code-server.tar.gz -C \ TERM="xterm" \
/app/code-server --strip-components=1 && \ S6_CMD_WAIT_FOR_SERVICES_MAXTIME="0" \
echo "**** clean up ****" && \ S6_VERBOSITY=1 \
apt-get clean && \ S6_STAGE2_HOOK=/docker-mods \
rm -rf \ VIRTUAL_ENV=/lsiopy \
/config/* \ PATH="/lsiopy/bin:$PATH" \
/tmp/* \ HOME="/config"
/var/lib/apt/lists/* \
/var/tmp/* # set version for s6 overlay
ARG S6_OVERLAY_VERSION="3.1.6.2"
ARG S6_OVERLAY_ARCH="x86_64"
# add s6 overlay
ADD https://github.com/just-containers/s6-overlay/releases/download/v${S6_OVERLAY_VERSION}/s6-overlay-noarch.tar.xz /tmp
RUN tar -C / -Jxpf /tmp/s6-overlay-noarch.tar.xz
ADD https://github.com/just-containers/s6-overlay/releases/download/v${S6_OVERLAY_VERSION}/s6-overlay-${S6_OVERLAY_ARCH}.tar.xz /tmp
RUN tar -C / -Jxpf /tmp/s6-overlay-${S6_OVERLAY_ARCH}.tar.xz
# add s6 optional symlinks
ADD https://github.com/just-containers/s6-overlay/releases/download/v${S6_OVERLAY_VERSION}/s6-overlay-symlinks-noarch.tar.xz /tmp
RUN tar -C / -Jxpf /tmp/s6-overlay-symlinks-noarch.tar.xz
ADD https://github.com/just-containers/s6-overlay/releases/download/v${S6_OVERLAY_VERSION}/s6-overlay-symlinks-arch.tar.xz /tmp
RUN tar -C / -Jxpf /tmp/s6-overlay-symlinks-arch.tar.xz && \
useradd -u 911 -U -d /config -s /bin/false abc && \
usermod -G users abc && \
mkdir -p \
/app \
/config \
/defaults \
/lsiopy
ARG MODS_VERSION="v3"
ARG PKG_INST_VERSION="v1"
ARG LSIOWN_VERSION="v1"
ADD --chmod=744 "https://raw.githubusercontent.com/linuxserver/docker-mods/mod-scripts/docker-mods.${MODS_VERSION}" "/docker-mods"
ADD --chmod=744 "https://raw.githubusercontent.com/linuxserver/docker-mods/mod-scripts/package-install.${PKG_INST_VERSION}" "/etc/s6-overlay/s6-rc.d/init-mods-package-install/run"
ADD --chmod=744 "https://raw.githubusercontent.com/linuxserver/docker-mods/mod-scripts/lsiown.${LSIOWN_VERSION}" "/usr/bin/lsiown"
# 安装达梦数据库
RUN mkdir -p /opt/dm8.zip && \
wget -O root/opt/dm8.zip https://download.dameng.com/eco/adapter/DM8/202401END/dm8_20240408_x86_rh7_64.zip
# add local files # add local files
COPY /root / COPY /root /
# ports and volumes # ports and volumes
EXPOSE 8443 EXPOSE 5000 3000 8443
ENTRYPOINT ["/init"]

View File

@ -0,0 +1 @@
oneshot

View File

@ -0,0 +1 @@
echo "[ls.io-init] done."

View File

@ -0,0 +1,12 @@
───────────────────────────────────────
_____ __ __ _____ _____ _____ _____
| | | | __|_ _| | |
| --| | |__ | | | | | | | | |
|_____|_____|_____| |_| |_____|_|_|_|
_____ __ __ _ __ ____
| __ | | | | | | \
| __ -| | | | |__| | |
|_____|_____|_|_____|____/
Based on images from linuxserver.io
───────────────────────────────────────

View File

@ -0,0 +1,32 @@
#!/usr/bin/with-contenv bash
# shellcheck shell=bash
PUID=${PUID:-911}
PGID=${PGID:-911}
groupmod -o -g "$PGID" abc
usermod -o -u "$PUID" abc
cat /etc/s6-overlay/s6-rc.d/init-adduser/branding
if [[ -f /donate.txt ]]; then
echo '
To support the app dev(s) visit:'
cat /donate.txt
fi
echo '
To support LSIO projects visit:
https://www.linuxserver.io/donate/
───────────────────────────────────────
GID/UID
───────────────────────────────────────'
echo "
User UID: $(id -u abc)
User GID: $(id -g abc)
───────────────────────────────────────
"
lsiown abc:abc /app
lsiown abc:abc /config
lsiown abc:abc /defaults

View File

@ -0,0 +1 @@
oneshot

View File

@ -0,0 +1 @@
/etc/s6-overlay/s6-rc.d/init-adduser/run

View File

@ -0,0 +1 @@
oneshot

View File

@ -0,0 +1 @@
# This file doesn't do anything, it's just the end of the downstream image init process

View File

@ -0,0 +1 @@
oneshot

View File

@ -0,0 +1 @@
# This file doesn't do anything, it's just the start of the downstream image init process

View File

@ -0,0 +1,31 @@
#!/usr/bin/with-contenv bash
# shellcheck shell=bash
for cron_user in abc root; do
if [[ -f "/etc/crontabs/${cron_user}" ]]; then
lsiown "${cron_user}":"${cron_user}" "/etc/crontabs/${cron_user}"
crontab -u "${cron_user}" "/etc/crontabs/${cron_user}"
fi
if [[ -f "/defaults/crontabs/${cron_user}" ]]; then
# make folders
mkdir -p \
/config/crontabs
# if crontabs do not exist in config
if [[ ! -f "/config/crontabs/${cron_user}" ]]; then
# copy crontab from system
if crontab -l -u "${cron_user}" >/dev/null 2>&1; then
crontab -l -u "${cron_user}" >"/config/crontabs/${cron_user}"
fi
# if crontabs still do not exist in config (were not copied from system)
# copy crontab from image defaults (using -n, do not overwrite an existing file)
cp -n "/defaults/crontabs/${cron_user}" /config/crontabs/
fi
# set permissions and import user crontabs
lsiown "${cron_user}":"${cron_user}" "/config/crontabs/${cron_user}"
crontab -u "${cron_user}" "/config/crontabs/${cron_user}"
fi
done

View File

@ -0,0 +1 @@
oneshot

View File

@ -0,0 +1 @@
/etc/s6-overlay/s6-rc.d/init-crontab-config/run

View File

@ -0,0 +1,22 @@
#!/usr/bin/with-contenv bash
# shellcheck shell=bash
# Directories
SCRIPTS_DIR="/custom-cont-init.d"
# Make sure custom init directory exists and has files in it
if [[ -e "${SCRIPTS_DIR}" ]] && [[ -n "$(/bin/ls -A ${SCRIPTS_DIR} 2>/dev/null)" ]]; then
echo "[custom-init] Files found, executing"
for SCRIPT in "${SCRIPTS_DIR}"/*; do
NAME="$(basename "${SCRIPT}")"
if [[ -f "${SCRIPT}" ]]; then
echo "[custom-init] ${NAME}: executing..."
/bin/bash "${SCRIPT}"
echo "[custom-init] ${NAME}: exited $?"
elif [[ ! -f "${SCRIPT}" ]]; then
echo "[custom-init] ${NAME}: is not a file"
fi
done
else
echo "[custom-init] No custom files found, skipping..."
fi

View File

@ -0,0 +1 @@
oneshot

View File

@ -0,0 +1 @@
/etc/s6-overlay/s6-rc.d/init-custom-files/run

View File

@ -0,0 +1,19 @@
#!/usr/bin/with-contenv bash
# shellcheck shell=bash
if find /run/s6/container_environment/FILE__* -maxdepth 1 > /dev/null 2>&1; then
for FILENAME in /run/s6/container_environment/FILE__*; do
SECRETFILE=$(cat "${FILENAME}")
if [[ -f ${SECRETFILE} ]]; then
FILESTRIP=${FILENAME//FILE__/}
if [[ $(tail -n1 "${SECRETFILE}" | wc -l) != 0 ]]; then
echo "[env-init] Your secret: ${FILENAME##*/}"
echo " contains a trailing newline and may not work as expected"
fi
cat "${SECRETFILE}" >"${FILESTRIP}"
echo "[env-init] ${FILESTRIP##*/} set from ${FILENAME##*/}"
else
echo "[env-init] cannot find secret in ${FILENAME##*/}"
fi
done
fi

View File

@ -0,0 +1 @@
oneshot

View File

@ -0,0 +1 @@
/etc/s6-overlay/s6-rc.d/init-envfile/run

View File

@ -0,0 +1,33 @@
#!/usr/bin/with-contenv bash
# shellcheck shell=bash
MIGRATIONS_DIR="/migrations"
MIGRATIONS_HISTORY="/config/.migrations"
echo "[migrations] started"
if [[ ! -d ${MIGRATIONS_DIR} ]]; then
echo "[migrations] no migrations found"
exit
fi
for MIGRATION in $(find ${MIGRATIONS_DIR}/* | sort -n); do
NAME="$(basename "${MIGRATION}")"
if [[ -f ${MIGRATIONS_HISTORY} ]] && grep -Fxq "${NAME}" ${MIGRATIONS_HISTORY}; then
echo "[migrations] ${NAME}: skipped"
continue
fi
echo "[migrations] ${NAME}: executing..."
chmod +x "${MIGRATION}"
# Execute migration script in a subshell to prevent it from modifying the current environment
("${MIGRATION}")
EXIT_CODE=$?
if [[ ${EXIT_CODE} -ne 0 ]]; then
echo "[migrations] ${NAME}: failed with exit code ${EXIT_CODE}, contact support"
exit "${EXIT_CODE}"
fi
echo "${NAME}" >>${MIGRATIONS_HISTORY}
echo "[migrations] ${NAME}: succeeded"
done
echo "[migrations] done"

View File

@ -0,0 +1 @@
oneshot

View File

@ -0,0 +1 @@
/etc/s6-overlay/s6-rc.d/init-migrations/run

View File

@ -0,0 +1 @@
oneshot

View File

@ -0,0 +1 @@
# This file doesn't do anything, it's just the end of the mod init process

View File

@ -0,0 +1 @@
/etc/s6-overlay/s6-rc.d/init-mods-package-install/run

View File

@ -0,0 +1 @@
oneshot

View File

@ -0,0 +1 @@
# This file doesn't do anything, it's just the start of the mod init process

View File

@ -0,0 +1 @@
oneshot

View File

@ -0,0 +1 @@
# This file doesn't do anything, it's just the end of the mod init process

View File

@ -0,0 +1 @@
oneshot

View File

@ -0,0 +1 @@
# This file doesn't do anything, it just signals that services can start

View File

@ -0,0 +1,15 @@
#!/usr/bin/with-contenv bash
# shellcheck shell=bash
if builtin command -v crontab >/dev/null 2>&1 && [[ -n "$(crontab -l -u abc 2>/dev/null || true)" || -n "$(crontab -l -u root 2>/dev/null || true)" ]]; then
if builtin command -v busybox >/dev/null 2>&1 && [[ $(busybox || true) =~ [[:space:]](crond)([,]|$) ]]; then
exec busybox crond -f -S -l 5
elif [[ -f /usr/bin/apt ]] && [[ -f /usr/sbin/cron ]]; then
exec /usr/sbin/cron -f -L 5
else
echo "**** cron not found ****"
sleep infinity
fi
else
sleep infinity
fi

View File

@ -0,0 +1 @@
longrun

View File

@ -1,15 +1,18 @@
#flask-app
FROM base FROM base
# 升级pip
RUN pip install --upgrade pip
# 创建一个用户运行flask # 创建一个用户运行flask
RUN useradd -m -s /bin/bash flask && \ RUN useradd -m -s /bin/bash flask && \
chown -R flask:flask /home/flask && \ chown -R flask:flask /home/flask && \
mkdir -p /var/log/flask-app && touch /var/log/flask-app/flask-app.err.log && touch /var/log/flask-app/flask-app.out.log && \ mkdir -p /var/log/flask-app && touch /var/log/flask-app/flask-app.err.log && touch /var/log/flask-app/flask-app.out.log && \
chown -R flask:flask /var/log/flask-app && \ chown -R flask:flask /var/log/flask-app \
service ssh start && \ && apt-get -y update \
service ssh restart && apt-get install -y --no-install-recommends \
python3 python3-dev python3-pip python3-venv \
&& apt-get clean \
&& rm -rf /config/* /tmp/* /var/lib/apt/lists/* /var/tmp/* \
&& pip install --upgrade pip
WORKDIR /home/flask WORKDIR /home/flask
USER flask USER flask

View File

@ -6,6 +6,7 @@ import paramiko
from teacher_func import * from teacher_func import *
from student_func import * from student_func import *
from k8s_func import *
from flask import Flask, render_template, request, jsonify, send_from_directory, session from flask import Flask, render_template, request, jsonify, send_from_directory, session
from flask_cors import CORS from flask_cors import CORS
@ -256,13 +257,11 @@ def SendTrainTest():
TrainJudge=data['TrainJudge'] TrainJudge=data['TrainJudge']
Hour=data['HourValue'] Hour=data['HourValue']
Min=data['MinValue'] Min=data['MinValue']
StopTime=data['StopTime']
Class=data['selectedItems'] Class=data['selectedItems']
Train=data['Train'] Train=data['Train']
teacher_id=data['teacher_ID'] teacher_id=data['teacher_ID']
startTime=data['startDate'] SendTrainTestFunc(TrainChoice, TrainCompletion, TrainJudge, Hour, Min, StopTime,Class,Train,teacher_id)
endTime=data['endDate']
SendTrainTestFunc(TrainChoice, TrainCompletion, TrainJudge, Hour, Min,Class,Train,teacher_id,startTime,endTime)
TeacherMark(Class,teacher_id)
return '发布成功' return '发布成功'
@ -271,14 +270,26 @@ def Find_details():
data=request.json data=request.json
ID=data['ID'] ID=data['ID']
result=Find_details_Func(ID) result=Find_details_Func(ID)
print(result)
return jsonify({'TestScore':result}) return jsonify({'TestScore':result})
@app.route("/api/teacher/list_pods") # 列出pod
def teacher_list_pods():
return list_pods()
@app.route("/api/teacher/list_services") # 列出服务
def teacher_list_services():
return list_services()
@app.route('/api/teacher/NotMarkTest',methods=["POST"]) @app.route("/api/teacher/create_pod") # 创建服务 0为项目实训 1为安装实训
def NotMark(): def teacher_create_pod():
testID=request.json['testID'] return create_pod(1, "test")
result=NotMarkTest(testID)
return jsonify({'result':result})
@app.route("/api/teacher/delete_pod") # 删除服务
def teacher_delete_pod():
return delete_pod("test")
@app.route("/api/teacher/check_pod") # 检测数据库是否安装成功 若成功返回OK 否则返回NO
def teacher_check_pod():
return check_dm("test")
@app.route('/') @app.route('/')
@app.route('/<path:path>') @app.route('/<path:path>')
@ -291,13 +302,14 @@ def handle_connect_ssh(data):
ip = data['ip'] ip = data['ip']
port = int(data['port']) port = int(data['port'])
password = data['password'] password = data['password']
user = data['user']
client_id = request.sid client_id = request.sid
print("connected to " + ip + " " + str(port) + " " + password)
ssh_client = paramiko.SSHClient() ssh_client = paramiko.SSHClient()
ssh_client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) ssh_client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
try: try:
ssh_client.connect(ip, port=port, username='your-username', password=password) ssh_client.connect(ip, port=port, username=user, password=password)
transport = ssh_client.get_transport() transport = ssh_client.get_transport()
channel = transport.open_session() channel = transport.open_session()
channel.get_pty() channel.get_pty()

View File

@ -8,12 +8,17 @@ metadata:
spec: spec:
containers: containers:
- name: base-dm - name: base-dm
image: harbor.dameng.io/cnsof50011836/base-dm image: harbor.dameng.io/cnsof50011836/base-dm:latest
imagePullPolicy: IfNotPresent imagePullPolicy: Always
command: [ "/bin/bash", "-c" ]
args: [ "service ssh start && tail -f /dev/null" ]
securityContext:
runAsUser: 0
runAsGroup: 0
resources: resources:
limits: limits:
cpu: '1' cpu: '1'
memory: 1Gi memory: 1Gi
requests: requests:
cpu: '0.25' cpu: '0.25'
memory: 0.5G memory: 0.5Gi

View File

@ -0,0 +1,20 @@
apiVersion: v1
kind: Service
metadata:
name: NAME
spec:
selector:
app: NAME
ports:
- protocol: TCP
port: 22
targetPort: 22
name: "ssh"
- protocol: TCP
port: 5236
targetPort: 5236
name: "dm"
type: ClusterIP

View File

@ -0,0 +1,22 @@
apiVersion: v1
kind: Pod
metadata:
name: NAME
namespace: ""
labels:
app: NAME
spec:
containers:
- name: code-server
image: harbor.dameng.io/cnsof50011836/code-server:latest
imagePullPolicy: Always
securityContext:
runAsUser: 0
runAsGroup: 0
resources:
limits:
cpu: '1'
memory: 1Gi
requests:
cpu: '0.25'
memory: 0.5Gi

View File

@ -0,0 +1,27 @@
apiVersion: v1
kind: Service
metadata:
name: NAME
spec:
selector:
app: NAME
ports:
- protocol: TCP
port: 8443
targetPort: 8443
name: "code"
appProtocol: HTTP
- protocol: TCP
port: 5000
targetPort: 5000
name: "flask"
appProtocol: HTTP
- protocol: TCP
port: 3000
targetPort: 3000
name: "frontend"
appProtocol: HTTP
type: NodePort

84
python/k8s_func.py Normal file
View File

@ -0,0 +1,84 @@
import json
import traceback
import yaml
from kubernetes import client, config
from flask import jsonify
import dmPython
# Load in-cluster config
config.load_incluster_config()
v1 = client.CoreV1Api()
namespace = open("/var/run/secrets/kubernetes.io/serviceaccount/namespace").read()
IP = "36.138.114.105"
def list_pods():
ret = v1.list_namespaced_pod(namespace, watch=False)
return {
"list": [{
"name": item.metadata.name,
"ip": item.status.pod_ip
} for item in ret.items]
}
def list_services():
ret = v1.list_namespaced_service(namespace)
return {
"list": [
item.to_dict()
for item in ret.items]
}
def create_pod(type, name):
# 读取 pod yaml 文件
with open(f"assets/type{type}-pod.yaml") as f:
pod_manifest = yaml.safe_load(f)
pod_manifest["metadata"]["name"] = name
pod_manifest["metadata"]["labels"]["app"] = name
# 创建 Pod
resp = v1.create_namespaced_pod(
body=pod_manifest,
namespace=namespace
)
print(f"pod '{resp.metadata.name}' 创建成功")
# 创建 Service
with open(f"assets/type{type}-service.yaml") as f:
service_pod = yaml.safe_load(f)
service_pod["metadata"]["name"] = name + "-service"
service_pod["spec"]["selector"]["app"] = name
resp = v1.create_namespaced_service(
body=service_pod,
namespace=namespace
)
print(f"服务 '{resp.metadata.name}' 创建成功")
if type == 1:
# 创建成功,再次查询,拿到端口
service = v1.read_namespaced_service(name=name + "-service", namespace=namespace)
print(service)
print("访问地址:" + IP + ":" + str(service.spec.ports[0].node_port))
else:
service = v1.read_namespaced_service(name=name + "-service", namespace=namespace)
print(service)
print("访问地址:" + IP + ":" + str(service.spec.ports[0].node_port))
return f"{IP} {service.spec.ports[0].node_port}"
def delete_pod(name):
v1.delete_namespaced_pod(name=name, namespace=namespace)
v1.delete_namespaced_service(name=name + "-service", namespace=namespace)
return "删除成功"
def check_dm(name):
try:
service = v1.read_namespaced_service(name=name + "-service", namespace=namespace)
db = dmPython.connect(user='SYSDBA', password='SYSDBA', host=service.spec.cluster_ip, port="5236")
cursor = db.cursor()
records = cursor.execute("SELECT * FROM V$VERSION").fetchall()
for record in records:
print(record)
return "OK"
except:
traceback.print_exc()
return "NO"