1
0
mirror of https://github.com/1Panel-dev/1Panel.git synced 2025-01-19 00:09:16 +08:00

feat: Docker 服务支持自定义 .sock 路径 (#3085)

Refs #2858
This commit is contained in:
ssongliu 2023-11-28 15:00:10 +08:00 committed by GitHub
parent e41661e8d4
commit 73b2804d68
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 195 additions and 8 deletions

View File

@ -3,10 +3,11 @@ package dto
import "time"
type SettingInfo struct {
UserName string `json:"userName"`
Email string `json:"email"`
SystemIP string `json:"systemIP"`
SystemVersion string `json:"systemVersion"`
UserName string `json:"userName"`
Email string `json:"email"`
SystemIP string `json:"systemIP"`
SystemVersion string `json:"systemVersion"`
DockerSockPath string `json:"dockerSockPath"`
SessionTimeout string `json:"sessionTimeout"`
LocalTime string `json:"localTime"`

View File

@ -56,6 +56,7 @@ func Init() {
migrations.UpdateAcmeAccount,
migrations.UpdateWebsiteSSL,
migrations.AddWebsiteCA,
migrations.AddDockerSockPath,
})
if err := m.Migrate(); err != nil {
global.LOG.Error(err)

View File

@ -35,3 +35,13 @@ var UpdateWebsiteSSL = &gormigrate.Migration{
return nil
},
}
var AddDockerSockPath = &gormigrate.Migration{
ID: "20231128-add-docker-sock-path",
Migrate: func(tx *gorm.DB) error {
if err := tx.Create(&model.Setting{Key: "DockerSockPath", Value: "unix:///var/run/docker.sock"}).Error; err != nil {
return err
}
return nil
},
}

View File

@ -32,9 +32,9 @@ import (
func Start() {
viper.Init()
log.Init()
app.Init()
db.Init()
migration.Init()
app.Init()
validator.Init()
gob.Register(psession.SessionUser{})
cache.Init()

View File

@ -2,6 +2,8 @@ package docker
import (
"context"
"github.com/1Panel-dev/1Panel/backend/app/model"
"github.com/1Panel-dev/1Panel/backend/global"
"github.com/docker/docker/api/types"
@ -14,7 +16,12 @@ type Client struct {
}
func NewClient() (Client, error) {
cli, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation())
var settingItem model.Setting
_ = global.DB.Where("key = ?", "DockerSockPath").First(&settingItem).Error
if len(settingItem.Value) == 0 {
settingItem.Value = "unix:///var/run/docker.sock"
}
cli, err := client.NewClientWithOpts(client.FromEnv, client.WithHost(settingItem.Value), client.WithAPIVersionNegotiation())
if err != nil {
return Client{}, err
}
@ -25,7 +32,12 @@ func NewClient() (Client, error) {
}
func NewDockerClient() (*client.Client, error) {
cli, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation())
var settingItem model.Setting
_ = global.DB.Where("key = ?", "DockerSockPath").First(&settingItem).Error
if len(settingItem.Value) == 0 {
settingItem.Value = "unix:///var/run/docker.sock"
}
cli, err := client.NewClientWithOpts(client.FromEnv, client.WithHost(settingItem.Value), client.WithAPIVersionNegotiation())
if err != nil {
return nil, err
}

View File

@ -16709,6 +16709,9 @@ const docTemplate = `{
"dingVars": {
"type": "string"
},
"dockerSockPath": {
"type": "string"
},
"email": {
"type": "string"
},

View File

@ -16702,6 +16702,9 @@
"dingVars": {
"type": "string"
},
"dockerSockPath": {
"type": "string"
},
"email": {
"type": "string"
},

View File

@ -2292,6 +2292,8 @@ definitions:
type: string
dingVars:
type: string
dockerSockPath:
type: string
email:
type: string
emailVars:

View File

@ -7,6 +7,7 @@ export namespace Setting {
email: string;
systemIP: string;
systemVersion: string;
dockerSockPath: string;
sessionTimeout: number;
localTime: string;

View File

@ -744,6 +744,12 @@ const message = {
daemonJsonPath: 'Conf Path',
serviceUnavailable: 'Docker service is not started at present, please click',
startIn: ' to start',
sockPath: 'Socket Path',
sockPathHelper: 'Communication channel between Docker Daemon and the client',
sockPathHelper1: 'Default value is unix:///var/run/docker-x.sock',
sockPathMsg:
'Saving the Socket Path setting may result in Docker service being unavailable. Do you want to continue?',
sockPathErr: 'Please select or enter the correct Docker sock file path',
},
cronjob: {
create: 'Create Cronjob',

View File

@ -715,6 +715,11 @@ const message = {
daemonJsonPath: '配置路徑',
serviceUnavailable: '當前未啟動 Docker 服務請在',
startIn: '中開啟',
sockPath: 'Socket 路徑',
sockPathHelper: 'Docker 守護進程Docker Daemon與客戶端之間的通信通道',
sockPathHelper1: '默認值為 unix:///var/run/docker-x.sock',
sockPathMsg: '保存設定 Socket 路徑可能導致 Docker 服務不可用是否繼續',
sockPathErr: '請選擇或輸入正確的 Docker sock 文件路徑',
},
cronjob: {
create: '創建計劃任務',

View File

@ -716,6 +716,11 @@ const message = {
daemonJsonPath: '配置路径',
serviceUnavailable: '当前未启动 Docker 服务请在',
startIn: '中开启',
sockPath: 'Socket 路径',
sockPathHelper: 'Docker 守护进程Docker Daemon与客户端之间的通信通道',
sockPathHelper1: '默认值为 unix:///var/run/docker-x.sock',
sockPathMsg: '保存设置 Socket 路径可能导致 Docker 服务不可用是否继续',
sockPathErr: '请选择或输入正确的 Docker sock 文件路径',
},
cronjob: {
create: '创建计划任务',

View File

@ -150,6 +150,16 @@
<el-radio label="systemd">systemd</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item :label="$t('container.sockPath')" prop="dockerSockPath">
<el-input disabled v-model="form.dockerSockPath">
<template #append>
<el-button @click="onChangeSockPath" icon="Setting">
{{ $t('commons.button.set') }}
</el-button>
</template>
</el-input>
<span class="input-help">{{ $t('container.sockPathHelper') }}</span>
</el-form-item>
</el-form>
</el-col>
</el-row>
@ -220,6 +230,7 @@
<Registry ref="registriesRef" @search="search" />
<LogOption ref="logOptionRef" @search="search" />
<Ipv6Option ref="ipv6OptionRef" @search="search" />
<SockPath ref="sockPathRef" @search="search" />
<ConfirmDialog ref="confirmDialogRefIpv6" @confirm="onSaveIPv6" @cancel="search" />
<ConfirmDialog ref="confirmDialogRefIptable" @confirm="onSubmitOpenIPtable" @cancel="search" />
<ConfirmDialog ref="confirmDialogRefLog" @confirm="onSubmitSaveLog" @cancel="search" />
@ -240,6 +251,7 @@ import Mirror from '@/views/container/setting/mirror/index.vue';
import Registry from '@/views/container/setting/registry/index.vue';
import LogOption from '@/views/container/setting/log/index.vue';
import Ipv6Option from '@/views/container/setting/ipv6/index.vue';
import SockPath from '@/views/container/setting/sock-path/index.vue';
import ConfirmDialog from '@/components/confirm-dialog/index.vue';
import i18n from '@/lang';
import {
@ -249,6 +261,7 @@ import {
updateDaemonJson,
updateDaemonJsonByfile,
} from '@/api/modules/container';
import { getSettingInfo } from '@/api/modules/setting';
import { MsgSuccess } from '@/utils/message';
import { checkNumberRange } from '@/global/form-rules';
@ -271,6 +284,7 @@ const confirmDialogRefIptable = ref();
const confirmDialogRefIpv6 = ref();
const logOptionShow = ref();
const ipv6OptionShow = ref();
const sockPathRef = ref();
const form = reactive({
isSwarm: false,
@ -290,12 +304,13 @@ const form = reactive({
logOptionShow: false,
logMaxSize: '',
logMaxFile: 3,
dockerSockPath: '',
});
const rules = reactive({
logMaxSize: [checkNumberRange(1, 1024000)],
logMaxFile: [checkNumberRange(1, 100)],
});
const formRef = ref<FormInstance>();
const dockerConf = ref();
const confirmDialogRefFile = ref();
@ -318,6 +333,10 @@ const onChangeRegistries = () => {
registriesRef.value.acceptParams({ registries: form.registries });
};
const onChangeSockPath = () => {
sockPathRef.value.acceptParams({ dockerSockPath: form.dockerSockPath });
};
const handleIPv6 = async () => {
if (form.ipv6) {
ipv6OptionRef.value.acceptParams({
@ -496,6 +515,9 @@ const search = async () => {
form.fixedCidrV6 = res.data.fixedCidrV6;
form.ip6Tables = res.data.ip6Tables;
form.experimental = res.data.experimental;
const settingRes = await getSettingInfo();
form.dockerSockPath = settingRes.data.dockerSockPath || 'unix:///var/run/docker-x.sock';
};
onMounted(() => {

View File

@ -0,0 +1,116 @@
<template>
<div>
<el-drawer v-model="drawerVisible" :destroy-on-close="true" :close-on-click-modal="false" size="30%">
<template #header>
<DrawerHeader :header="$t('container.sockPath')" :back="handleClose" />
</template>
<el-form
ref="formRef"
label-position="top"
:model="form"
:rules="rules"
@submit.prevent
v-loading="loading"
>
<el-row type="flex" justify="center">
<el-col :span="22">
<el-form-item :label="$t('container.sockPath')" prop="dockerSockPath">
<el-input placeholder="unix:///var/run/docker.sock" v-model="form.dockerSockPath">
<template #prepend>
<FileList @choose="loadBuildDir"></FileList>
</template>
</el-input>
<span class="input-help">{{ $t('container.sockPathHelper1') }}</span>
</el-form-item>
</el-col>
</el-row>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="drawerVisible = false">{{ $t('commons.button.cancel') }}</el-button>
<el-button :disabled="loading" type="primary" @click="onSubmit(formRef)">
{{ $t('commons.button.confirm') }}
</el-button>
</span>
</template>
</el-drawer>
</div>
</template>
<script lang="ts" setup>
import { reactive, ref } from 'vue';
import i18n from '@/lang';
import { MsgSuccess } from '@/utils/message';
import { updateSetting } from '@/api/modules/setting';
import DrawerHeader from '@/components/drawer-header/index.vue';
import { ElMessageBox, FormInstance } from 'element-plus';
const emit = defineEmits<{ (e: 'search'): void }>();
interface DialogProps {
dockerSockPath: string;
}
const drawerVisible = ref();
const loading = ref();
const form = reactive({
dockerSockPath: '',
});
const formRef = ref<FormInstance>();
const rules = reactive({
dockerSockPath: [{ required: true, validator: checkSockPath, trigger: 'blur' }],
});
function checkSockPath(rule: any, value: any, callback: any) {
if (!value.endsWith('.sock')) {
return callback(new Error(i18n.global.t('container.sockPathErr')));
}
callback();
}
const acceptParams = (params: DialogProps): void => {
form.dockerSockPath = params.dockerSockPath;
drawerVisible.value = true;
};
const loadBuildDir = async (path: string) => {
form.dockerSockPath = path;
};
const onSubmit = async (formEl: FormInstance | undefined) => {
if (!formEl) return;
formEl.validate(async (valid) => {
if (!valid) return;
ElMessageBox.confirm(i18n.global.t('container.sockPathMsg'), i18n.global.t('container.sockPath'), {
confirmButtonText: i18n.global.t('commons.button.confirm'),
cancelButtonText: i18n.global.t('commons.button.cancel'),
type: 'info',
}).then(async () => {
loading.value = true;
let params = {
key: 'DockerSockPath',
value: form.dockerSockPath.startsWith('unix://')
? form.dockerSockPath
: 'unix://' + form.dockerSockPath,
};
await updateSetting(params)
.then(() => {
loading.value = false;
handleClose();
emit('search');
MsgSuccess(i18n.global.t('commons.msg.operationSuccess'));
})
.catch(() => {
loading.value = false;
});
});
});
};
const handleClose = () => {
drawerVisible.value = false;
};
defineExpose({
acceptParams,
});
</script>