Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3a1e386929 | ||
|
|
e16165bfef | ||
|
|
2b2745d1ab | ||
|
|
7a4ebdbb2a | ||
|
|
650f633870 | ||
|
|
ff2fc35963 | ||
|
|
75593a32c0 | ||
|
|
fb69d04f92 | ||
|
|
0add342efb | ||
|
|
c8fb1d5c74 | ||
|
|
f78bb9f547 | ||
|
|
4b14d832c5 | ||
|
|
cd5fa0ed4d | ||
|
|
27a5047559 | ||
|
|
21e31863f3 | ||
|
|
b01350c977 | ||
|
|
00bab8a829 | ||
|
|
86199f6190 | ||
|
|
f02b6bace7 | ||
|
|
fe95f27dbb | ||
|
|
c128cbd8a8 | ||
|
|
0539704a31 | ||
|
|
7b89b526dd | ||
|
|
ccb856d878 | ||
|
|
c072303a97 | ||
|
|
0d8ebba0f6 | ||
|
|
c407a7cdfc |
@@ -0,0 +1,321 @@
|
||||
---
|
||||
title: ArchLinux
|
||||
date: 2025-07-28 10:26:05
|
||||
tags:
|
||||
---
|
||||
|
||||
# WSL
|
||||
|
||||
## 安装
|
||||
|
||||
### 在线安装
|
||||
|
||||
```powershell
|
||||
wsl --install archlinux
|
||||
```
|
||||
|
||||
# 包管理器 pacman
|
||||
|
||||
> [pacman - Arch Linux 中文维基](https://wiki.archlinuxcn.org/wiki/Pacman)
|
||||
|
||||
## 安装软件
|
||||
|
||||
```shell
|
||||
pacman -S fastfetch
|
||||
```
|
||||
|
||||
## 更新库
|
||||
|
||||
```shell
|
||||
pacman -Syyu
|
||||
```
|
||||
|
||||
# Vim设置
|
||||
|
||||
编辑当前用户下的vim配置文件`~/.vimrc`
|
||||
|
||||
```shell
|
||||
if has('mouse')
|
||||
set mouse-=a
|
||||
endif
|
||||
|
||||
set number
|
||||
syntax on
|
||||
set ignorecase
|
||||
set t_Co=256
|
||||
```
|
||||
|
||||
# Containerd + Nerdctl
|
||||
|
||||
## 安装
|
||||
|
||||
**1. 更新系统**
|
||||
|
||||
首先,确保你的 Arch Linux 系统是最新的:
|
||||
|
||||
```Bash
|
||||
sudo pacman -Syu
|
||||
```
|
||||
|
||||
**2. 安装 Containerd**
|
||||
|
||||
Containerd 是一个核心的容器运行时。它作为 `containerd` 包在官方仓库中提供。
|
||||
|
||||
```Bash
|
||||
sudo pacman -S containerd
|
||||
```
|
||||
|
||||
安装完成后,你需要启动并启用 Containerd 服务,以便它在系统启动时自动运行:
|
||||
|
||||
```Bash
|
||||
sudo systemctl enable --now containerd
|
||||
```
|
||||
|
||||
你可以通过以下命令检查 Containerd 的运行状态:
|
||||
|
||||
```Bash
|
||||
sudo systemctl status containerd
|
||||
```
|
||||
|
||||
确保它显示为 `active (running)`。
|
||||
|
||||
**3.安装Nerdctl**
|
||||
|
||||
```bash
|
||||
sudo pacman -S nerdctl
|
||||
```
|
||||
|
||||
**4.安装CNI Plugin**
|
||||
|
||||
> [Releases · containernetworking/plugins (github.com)](https://github.com/containernetworking/plugins/releases)
|
||||
|
||||
从Github上下载
|
||||
|
||||
```bash
|
||||
wget https://github.com/containernetworking/plugins/releases/download/v1.7.1/cni-plugins-linux-amd64-v1.7.1.tgz
|
||||
```
|
||||
|
||||
解压到指定目录`/opt/cni/bin`
|
||||
|
||||
```bash
|
||||
tar -zxvf cni-plugins-linux-amd64-v1.7.1.tgz -C /opt/cni/bin
|
||||
```
|
||||
|
||||
即可完成安装
|
||||
|
||||
可以验证下
|
||||
|
||||
```bash
|
||||
nerdctl run -it hello-world
|
||||
```
|
||||
|
||||
不报错,并且输出了结果,说明已经安装好了 CNI Plugin。
|
||||
|
||||

|
||||
|
||||
**5.安装Buildkit**
|
||||
|
||||
> [Release v0.23.2 · moby/buildkit (github.com)](https://github.com/moby/buildkit/releases/tag/v0.23.2)
|
||||
|
||||
下载 BuildKit 二进制文件:
|
||||
|
||||
```bash
|
||||
wget https://github.com/moby/buildkit/releases/download/v0.23.2/buildkit-v0.23.2.linux-amd64.tar.gz
|
||||
```
|
||||
|
||||
解压到临时目录下
|
||||
|
||||
```bash
|
||||
tar -zxvf
|
||||
```
|
||||
|
||||
安装 `buildctl` 和 `buildkitd`
|
||||
|
||||
将解压后的 `bin` 目录中的 `buildctl` 和 `buildkitd` 可执行文件移动到系统 `$PATH` 中的某个目录,例如 `/usr/local/bin`。
|
||||
|
||||
```bash
|
||||
sudo mv /tmp/bin/buildctl /usr/local/bin/
|
||||
sudo mv /tmp/bin/buildkitd /usr/local/bin/
|
||||
```
|
||||
|
||||
验证 `buildctl` 是否在 `$PATH` 中
|
||||
|
||||
```bash
|
||||
which buildctl
|
||||
buildctl version
|
||||
```
|
||||
|
||||
如果显示路径和版本信息,说明 `buildctl` 已经正确安装并可执行。
|
||||
|
||||
启动 BuildKit 守护进程 (`buildkitd`)
|
||||
|
||||
配置为 Systemd 服务
|
||||
|
||||
创建一个 systemd service 文件,例如 `/etc/systemd/system/buildkit.service`
|
||||
|
||||
```toml
|
||||
[Unit]
|
||||
Description=BuildKit Daemon
|
||||
Documentation=https://github.com/moby/buildkit
|
||||
|
||||
[Service]
|
||||
ExecStart=/usr/local/bin/buildkitd --addr unix:///run/buildkit/buildkitd.sock
|
||||
Type=notify
|
||||
Delegate=yes
|
||||
KillMode=process
|
||||
# 在某些环境中,可能需要调整用户和组
|
||||
# User=buildkit
|
||||
# Group=buildkit
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
```
|
||||
|
||||
保存后,重载 systemd 并启动服务
|
||||
|
||||
```bash
|
||||
sudo systemctl daemon-reload
|
||||
sudo systemctl enable buildkit # 设置开机自启
|
||||
sudo systemctl start buildkit
|
||||
```
|
||||
|
||||
检查 BuildKit 状态
|
||||
|
||||
```bash
|
||||
sudo systemctl status buildkit
|
||||
```
|
||||
|
||||

|
||||
|
||||
配置buildkitd镜像加速,解决构建时的镜像拉取问题
|
||||
|
||||
**BuildKit Daemon 的配置文件 (`buildkitd.toml`):** BuildKit 守护进程 (buildkitd) 可以通过配置文件进行更高级的配置,通常是 `/etc/buildkit/buildkitd.toml`(或 rootless 模式下的 `~/.config/buildkit/buildkitd.toml`)。在这个文件中,可以配置:
|
||||
|
||||
- **Registry Mirrors (镜像加速器/代理):** 为特定仓库定义镜像源,例如将 `docker.io` 的请求重定向到私有加速器。
|
||||
|
||||
```bash
|
||||
mkdir -p /etc/buildkit
|
||||
vim /etc/buildkit/buildkitd.toml
|
||||
```
|
||||
|
||||
添加以下内容
|
||||
```toml
|
||||
# registry configures a new Docker register used for cache import or output.
|
||||
[registry."docker.io"]
|
||||
# mirror configuration to handle path in case a mirror registry requires a /project path rather than just a host:port
|
||||
mirrors = ["https://docker.m.daocloud.io",
|
||||
"https://docker.imgdb.de",
|
||||
"https://docker-0.unsee.tech",
|
||||
"https://docker.hlmirror.com",
|
||||
"https://docker.1ms.run",
|
||||
"https://cjie.eu.org",
|
||||
"https://func.ink",
|
||||
"https://lispy.org",
|
||||
"https://docker.xiaogenban1993.com"]
|
||||
# Use plain HTTP to connect to the mirrors.
|
||||
http = true
|
||||
```
|
||||
|
||||
保存后,重启服务生效
|
||||
|
||||
```bash
|
||||
systemctl restart buildkit
|
||||
```
|
||||
|
||||
|
||||
|
||||
## Containerd的config.toml实现镜像加速
|
||||
|
||||
> [containerd/docs/cri/config.md at main · containerd/containerd](https://github.com/containerd/containerd/blob/main/docs/cri/config.md#registry-configuration)
|
||||
|
||||
如果没有`/etc/containerd/config.toml`,执行以下命令生成默认配置
|
||||
|
||||
```bash
|
||||
sudo containerd config default | sudo tee /etc/containerd/config.toml
|
||||
```
|
||||
|
||||
编辑Containerd的配置文件,添加以下镜像配置
|
||||
|
||||
```toml
|
||||
# 找到[plugins.'io.containerd.grpc.v1.cri']配置处
|
||||
[plugins.'io.containerd.grpc.v1.cri']
|
||||
disable_tcp_service = true
|
||||
stream_server_address = '127.0.0.1'
|
||||
stream_server_port = '0'
|
||||
stream_idle_timeout = '4h0m0s'
|
||||
enable_tls_streaming = false
|
||||
|
||||
[plugins.'io.containerd.grpc.v1.cri'.x509_key_pair_streaming]
|
||||
tls_cert_file = ''
|
||||
tls_key_file = ''
|
||||
|
||||
[plugins."io.containerd.grpc.v1.cri".containerd]
|
||||
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes]
|
||||
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc]
|
||||
runtime_type = "io.containerd.runc.v2"
|
||||
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options]
|
||||
SystemdCgroup = true
|
||||
|
||||
[plugins."io.containerd.grpc.v1.cri".registry] #在这里增加
|
||||
config_path = "/etc/containerd/certs.d"
|
||||
```
|
||||
|
||||
创建目录`/etc/containerd/certs.d/docker.io`
|
||||
|
||||
```shell
|
||||
mkdir -p /etc/containerd/certs.d/docker.io
|
||||
```
|
||||
|
||||
进入到创建好的目录下,编辑文件`hosts.toml`
|
||||
|
||||
```toml
|
||||
server = "https://docker.io"
|
||||
|
||||
[host."https://docker.m.daocloud.io"]
|
||||
capabilities = ["pull", "resolve"]
|
||||
|
||||
[host."https://docker.imgdb.de"]
|
||||
capabilities = ["pull", "resolve"]
|
||||
```
|
||||
|
||||
然后重启`containerd`服务即可
|
||||
|
||||
```shell
|
||||
systemctl restart containerd
|
||||
```
|
||||
|
||||
## containerd管理命令介绍
|
||||
|
||||
使用docker作为容器运行时需要经过多层转换(kubelet <-> dockershim <-> docker <-> containerd),这会导致连接不稳定和性能下降。K8s从v1.24版本开始,不再支持docker容器运行时,而是默认使用containerd
|
||||
|
||||
切换到containerd之后,有以下几种替代docker的管理命令:
|
||||
|
||||
使用k8s自带的crictl命令。crictl是一个符合CRI接口规范的命令行工具,可以用它来检查和管理kubelet节点上的容器运行时和镜像。
|
||||
使用containerd自带的ctr命令。ctr是一个本地CLI工具,可以用它来管理镜像、容器、任务、快照等。因为containerd支持多个命名空间,所以ctr命令需要指定命名空间。要管理k8s创建的容器,需要使用k8s.io名字空间,即ctr -n k8s.io。
|
||||
使用containerd额外提供的nerdctl工具。nerdctl是一个与docker兼容的containerd的命令行工具,需要额外安装。它支持一些docker没有的功能,比如延迟拉取镜像、镜像加密等。
|
||||
使用其他第三方管理容器的开源工具。
|
||||
|
||||
## docker、crictl和ctr命令对比
|
||||
|
||||
| 命令 | docker | crictl(k8s) | ctr(containerd) | nerdctl(containerd) |
|
||||
| ------------------- | ----------------- | -------------------------------- | ---------------------------- | --------------------- |
|
||||
| 查看运行的容器 | docker ps | crictl ps | ctr task ls/ctr container ls | nerdctl ps |
|
||||
| 查看镜像 | docker images | crictl images | ctr image ls | nerdctl images |
|
||||
| 查看容器日志 | docker logs | crictl logs | 无 | nerdctl logs |
|
||||
| 查看容器信息 | docker inspect | crictl inspect | ctr container info | nerdctl inspect |
|
||||
| 查看容器资源使用 | docker stats | crictl stats | 无 | nerdctl stats |
|
||||
| 启动/关闭已有的容器 | docker start/stop | crictl start/stop | ctr task start/kill | nerdctl start/stop |
|
||||
| 运行一个新的容器 | docker run | 比较麻烦,因为它的最小单元为 Pod | ctr run | nerdctl run |
|
||||
| 创建一个新的容器 | docker create | 比较麻烦,因为它的最小单元为 Pod | ctr container create | nerdctl create |
|
||||
| 在容器内部执行命令 | docker exec | crictl exec | 无 | nerdctl exec |
|
||||
| 删除容器 | docker rm | crictl rm | ctr container rm | nerdctl rm |
|
||||
| 删除镜像 | docker rmi | crictl rmi | ctr image rm | nerdctl rmi |
|
||||
| 导入镜像 | docker load | 无 | ctr image import | nerdctl load |
|
||||
| 导出镜像 | docker save | 无 | ctr image export | nerdctl save |
|
||||
| 拉取镜像 | docker pull | crictl pull | ctr image pull | nerdctl pull |
|
||||
| 给镜像打标签 | docker tag | 无 | ctr image tag | nerdctl tag |
|
||||
| 推送镜像 | docker push | 无 | ctr image push | nerdctl push |
|
||||
| 构建镜像 | docker build | 无 | 无 | nerdctl build |
|
||||
|
||||
(需要额外安装buildkit服务)
|
||||
注意:ctr和nerdctl命令需要指定名字空间,管理k8s创建的容器,需要使用k8s.io名字空间,即ctr/nerdctl -n k8s.io。
|
||||
@@ -80,6 +80,32 @@ docker compose down
|
||||
docker compose --project-name dify-docker down
|
||||
```
|
||||
|
||||
## 修改Dockerfile后,通过Docker Compose重新构建镜像
|
||||
|
||||
1. **修改 `Dockerfile`**。
|
||||
|
||||
2. 进入到 `Dockerfile` 和 `docker-compose.yml` 所在的目录。
|
||||
|
||||
3. **构建新镜像:**
|
||||
|
||||
Bash
|
||||
|
||||
```
|
||||
docker-compose build jenkins
|
||||
```
|
||||
|
||||
(如果遇到问题或想完全重来,可以加 `--no-cache`:`docker-compose build --no-cache jenkins`)
|
||||
|
||||
4. **使用新镜像启动容器:**
|
||||
|
||||
Bash
|
||||
|
||||
```
|
||||
docker-compose up -d --force-recreate jenkins
|
||||
```
|
||||
|
||||
执行这些步骤后,你的 Jenkins 容器就会运行在新修改并构建的 Docker 镜像上,其中包含了你所有新增的工具和配置。
|
||||
|
||||
|
||||
|
||||
# 集群搭建
|
||||
@@ -297,3 +323,73 @@ services:
|
||||
|
||||
```
|
||||
|
||||
## Oracle-12C
|
||||
|
||||
docker-compose.yaml
|
||||
|
||||
```yaml
|
||||
services:
|
||||
server:
|
||||
image: truevoly/oracle-12c
|
||||
container_name: oracle-12c
|
||||
volumes:
|
||||
- /etc/localtime:/etc/localtime:ro
|
||||
- /etc/timezone:/etc/timezone:ro
|
||||
- /var/oracle:/u01/app/oracle
|
||||
ports:
|
||||
- "2122:22"
|
||||
- "1521:1521"
|
||||
- "9090:8080"
|
||||
```
|
||||
|
||||
首先创建挂载目录,并赋予权限
|
||||
|
||||
```bash
|
||||
mkdir -p /var/oracle && chmod 777 /var/oracle
|
||||
```
|
||||
|
||||
启动
|
||||
|
||||
```bash
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
连接Oracle数据库
|
||||
|
||||
```yml
|
||||
hostname: localhost #主机名
|
||||
port: 1521 #端口号
|
||||
sid: xe
|
||||
service name: xe #服务名
|
||||
username: system #用户名
|
||||
password: oracle #密码
|
||||
```
|
||||
|
||||
```bash
|
||||
sqlplus system/oracle@localhost:1521/xe
|
||||
|
||||
sqlplus /nolog
|
||||
conn sys/oracle@localhost:1521/xe as sysdba
|
||||
```
|
||||
|
||||
使用 `sqlplus / as sysdba`登录
|
||||
|
||||
```bash
|
||||
su - oracle
|
||||
export ORACLE_HOME=/u01/app/oracle/product/12.1.0/xe
|
||||
export ORACLE_SID=xe
|
||||
export PATH=$ORACLE_HOME/bin:$PATH
|
||||
sqlplus / as sysdba
|
||||
```
|
||||
|
||||
环境变量永久生效
|
||||
|
||||
```bash
|
||||
echo 'export ORACLE_HOME=/u01/app/oracle/product/12.1.0/xe' >> ~/.bashrc
|
||||
echo 'export ORACLE_SID=xe' >> ~/.bashrc
|
||||
echo 'export PATH=$ORACLE_HOME/bin:$PATH' >> ~/.bashrc
|
||||
source ~/.bashrc
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -281,6 +281,22 @@ docker run -p 8080:8080
|
||||
--link=[]: 添加链接到另一个容器;
|
||||
--expose=[]: 开放一个端口或一组端口;
|
||||
--volume , -v 绑定一个卷
|
||||
--restart:重启策略:
|
||||
|
||||
- **`no`** – 此策略永远不会自动启动容器。这是使用 `docker run` 创建的所有容器的默认策略。
|
||||
- **`always`** – Docker 将确保容器始终运行。如果容器停止,它将立即重新启动。您仍然可以使用 `docker stop` 手动停止容器,但 Docker 会在下次守护进程重新启动时将其恢复。
|
||||
- **`on-failure`** – 如果容器因错误而停止,它将重新启动。守护进程重启后,Docker 不会启动容器。
|
||||
|
||||
`on-failure` 重启策略允许您指定应尝试重试的次数。如果连续多次启动失败,Docker 将放弃并让容器处于停止状态。
|
||||
|
||||
```sql
|
||||
docker run httpd:latest --restart on-failure:5
|
||||
```
|
||||
|
||||
在此示例中,Docker 将在失败(非零退出代码)后尝试重新启动容器五次。如果容器在第五次尝试时启动失败,将不再尝试重试。此选项对于在没有手动干预的情况下不太可能解决持续启动错误的容器很有用。
|
||||
- **`unless-stopped`** – 其功能类似于`always`。不同之处在于,如果容器已被手动停止,Docker 将永远不会重新启动容器。
|
||||
|
||||
|
||||
|
||||
### 启动容器
|
||||
|
||||
@@ -921,7 +937,8 @@ docker images
|
||||
```shell
|
||||
cd /usr/local
|
||||
mkdir jenkins_home
|
||||
docker run -d -uroot -p 8889:8080 -p 50000:50000 --name jenkins -v /usr/bin/docker:/usr/bin/docker -v /var/run/docker.sock:/var/run/docker.sock -v /etc/sysconfig/docker:/etc/sysconfig/docker -v /usr/local/jenkins_home:/var/jenkins_home -v /etc/localtime:/etc/localtime jenkins/jenkins
|
||||
docker run -d -uroot -p 8889:8080 -p 50000:50000 --name jenkins -v /usr/bin/docker:/usr/bin/docker -v /var/run/docker.sock:/var/run/docker.sock -v /etc/sysconfig/docker:/etc/sysconfig/docker -v /usr/local/jenkins_home:/var/jenkins_home -v /etc/localtime:/etc/localtime
|
||||
-u root jenkins/jenkins
|
||||
```
|
||||
|
||||
启动后查看日志
|
||||
|
||||
@@ -122,23 +122,23 @@ git stash list
|
||||
> id_rsa.pub是公钥
|
||||
|
||||
5. SourceTree配置
|
||||

|
||||

|
||||
启动 **PuTTY Key Generator**
|
||||
|
||||
6. 依次点击
|
||||

|
||||

|
||||
|
||||
7. PPKfile version 选择 2
|
||||

|
||||

|
||||
|
||||
8. 选择之前生成的id_rsa
|
||||

|
||||

|
||||
|
||||
9. 出现如下,选择 **Save private key** 保存秘钥
|
||||

|
||||

|
||||
|
||||
10. 保存到 ~/.ssh 目录即可
|
||||

|
||||

|
||||
|
||||
11. 在 **Sourcetree** 中 **工具** -> **选项** 中选择刚刚保存的 ppk文件即可
|
||||
|
||||
@@ -159,7 +159,108 @@ ssh-keygen -c -C "new_comment" -f ssh_key_path
|
||||
git checkout -- <filename or directory>
|
||||
```
|
||||
|
||||
## 撤回(重置)本地仓库提交
|
||||
|
||||
若想把已经提交到本地仓库的提交再撤回到本地,通常有几种情况和对应的命令。最常用的是 `git reset`。
|
||||
|
||||
`git reset` 命令可以用来将当前分支的 `HEAD` 指针移动到指定的提交,并根据不同的模式来处理**暂存区**和**工作目录**。
|
||||
|
||||
- ### 1. `git reset --soft <commit>`
|
||||
|
||||
|
||||
|
||||
- **作用:** 将 `HEAD` 指针移动到指定的 `<commit>`,但**保留**工作目录和暂存区的内容。这意味着你的文件会回到该 `<commit>` 时的状态,但是你当前的修改和暂存的修改都会保留。
|
||||
|
||||
- **适用场景:** 你提交了一个 commit,但是发现提交信息写错了,或者少提交了一些文件。你可以用 `--soft` 回退到上一个 commit,然后修改文件,重新提交。
|
||||
|
||||
- **示例:**
|
||||
|
||||
```Bash
|
||||
git reset --soft HEAD~1
|
||||
```
|
||||
|
||||
这会将 `HEAD` 回退到上一个提交(`HEAD~1` 表示上一个提交)。
|
||||
|
||||
- ### 2. `git reset --mixed <commit>` (默认模式)
|
||||
|
||||
|
||||
|
||||
- **作用:** 将 `HEAD` 指针移动到指定的 `<commit>`,并**清空**暂存区,但**保留**工作目录的内容。这意味着你的文件会回到该 `<commit>` 时的状态,你当前的修改会保留在工作目录中(未暂存)。
|
||||
|
||||
- **适用场景:** 你提交了一个 commit,但是发现这个 commit 的内容不对,想撤销提交,并重新暂存和提交。
|
||||
|
||||
- **示例:**
|
||||
|
||||
```Bash
|
||||
git reset HEAD~1
|
||||
# 或者 git reset --mixed HEAD~1
|
||||
```
|
||||
|
||||
这会将 `HEAD` 回退到上一个提交,并将暂存区清空,但保留文件在工作目录。
|
||||
|
||||
|
||||
|
||||
- ### 3. `git reset --hard <commit>`
|
||||
|
||||
|
||||
|
||||
- **作用:** 将 `HEAD` 指针移动到指定的 `<commit>`,并**清空**暂存区和**丢弃**工作目录的所有修改。这意味着你的仓库会完全回到该 `<commit>` 时的状态,所有在该 `<commit>` 之后的修改都会丢失,**这是最危险的操作**。
|
||||
|
||||
- **适用场景:** 你想完全放弃当前分支上的所有最新修改和提交,回到之前的某个干净的状态。
|
||||
|
||||
- **示例:**
|
||||
|
||||
```Bash
|
||||
git reset --hard HEAD~1
|
||||
```
|
||||
|
||||
这会将 `HEAD` 回退到上一个提交,并丢弃所有工作目录和暂存区的修改。
|
||||
|
||||
|
||||
|
||||
## 如何找到 `<commit>` 的 ID?
|
||||
|
||||
|
||||
|
||||
你可以使用 `git log` 命令来查看提交历史,并找到你想要回退到的提交的哈希值(commit ID)。
|
||||
|
||||
Bash
|
||||
|
||||
```
|
||||
git log
|
||||
```
|
||||
|
||||
`git log` 会显示类似这样的信息:
|
||||
|
||||
```
|
||||
commit abcdef1234567890abcdef1234567890abcdef (HEAD -> master)
|
||||
Author: Your Name <your.email@example.com>
|
||||
Date: Fri Aug 1 13:20:00 2025 +0800
|
||||
|
||||
最新的提交
|
||||
|
||||
commit fedcba0987654321fedcba0987654321fedcba (origin/master)
|
||||
Author: Another Name <another.email@example.com>
|
||||
Date: Thu Jul 31 10:00:00 2025 +0800
|
||||
|
||||
之前的提交
|
||||
```
|
||||
|
||||
你可以复制 `commit` 后面的哈希值(例如 `fedcba0987654321...`)来替换上面的 `<commit>`。
|
||||
|
||||
## git 如何关闭commit时的语法检测 ---husky
|
||||
|
||||
1 报错提示
|
||||
git commit提交时报错如下:
|
||||
|
||||
husky+>+pre-commit+(node+v14.18.2)
|
||||
|
||||
2 解决方案
|
||||
1:卸载husky。只要把项目的package.json文件中devDependencies节点下的husky库删掉,然后重新npm i 一次即可。或者直接在项目根目录下执行npm uninstall husky --save也可以,再次提交,自动化测试功能就屏蔽掉
|
||||
|
||||
2:进入项目的.git文件夹(文件夹默认隐藏,可先设置显示或者命令ls查找),再进入hooks文件夹,删除pre-commit文件,重新git commit -m ‘xxx’ git push即可
|
||||
|
||||
3:将git commit -m “XXX” 改为 git commit --no-verify -m “xxx”
|
||||
|
||||
# github
|
||||
|
||||
@@ -204,10 +305,10 @@ git config --global https.proxy 'http://127.0.0.1:代理的port'
|
||||
5. 右侧下拉框 **Generate new token (classic)**
|
||||
|
||||
6. 按以下配置
|
||||

|
||||

|
||||
|
||||
7. 得到 token
|
||||

|
||||

|
||||
|
||||
8. 修改现有项目的url
|
||||
```shell
|
||||
@@ -216,3 +317,71 @@ git config --global https.proxy 'http://127.0.0.1:代理的port'
|
||||
|
||||
|
||||
|
||||
# Gitea
|
||||
|
||||
## 备份
|
||||
|
||||
数据库备份至postgresql
|
||||
|
||||
```shell
|
||||
docker exec -u git -it -w /tmp gitea bash -c '/app/gitea/gitea dump --database postgres --config /data/gitea/conf/app.ini'
|
||||
```
|
||||
|
||||
# Sourcetree
|
||||
|
||||
这里主要介绍两种最常用的场景,对应 `git reset --soft` 和 `git reset --hard` 的效果。
|
||||
|
||||
## 撤回(重置)本地仓库提交
|
||||
|
||||
### 1. 撤销最近一次提交(保留修改以便重新提交)
|
||||
|
||||
|
||||
|
||||
这类似于 `git reset --soft HEAD~1` 或 `git reset --mixed HEAD~1` 的效果,目的是撤销提交,但保留你的文件修改。
|
||||
|
||||
1. **打开日志/历史记录:** 在 SourceTree 界面的左侧,找到你的仓库,然后点击顶部的“日志/历史”或“历史记录”选项卡。
|
||||
|
||||
2. **定位要撤销的提交:** 在提交历史列表中,找到你想撤销的**前一个**提交(也就是你希望回退到的那个提交)。
|
||||
|
||||
3. **右键点击并选择:** 右键点击该提交。
|
||||
|
||||
4. **选择“将当前分支重置到此提交”:** 在弹出的菜单中选择 **“将当前分支重置到此提交”** (Reset current branch to this commit)。
|
||||

|
||||
|
||||
5. **选择重置模式:** 此时会出现一个弹窗,让你选择重置模式:
|
||||
|
||||
- **Soft(软重置)**:勾选这个选项。它会将 `HEAD` 指针移动到选定的提交,**保留**工作目录和暂存区的内容。这意味着你的修改还在,只是不再是提交的一部分。
|
||||
- **Mixed(混合重置)**:这是默认选项。它会将 `HEAD` 指针移动到选定的提交,**清空**暂存区,但**保留**工作目录的内容。
|
||||
- **注意:** 如果你只想撤销提交,并打算修改后重新提交,通常选择 **Soft** 或 **Mixed** 都可以,根据你是否希望文件保留在暂存区。对于“撤回本地仓库提交”这个需求,通常是希望保留修改以便重新操作。
|
||||
|
||||

|
||||
|
||||
6. **确认:** 点击“确定”或“Reset”按钮。
|
||||
|
||||
完成这些步骤后,你会发现最新的那个提交消失了,而你工作目录中的文件依然保留了修改内容,你可以重新暂存并提交。
|
||||
|
||||
------
|
||||
|
||||
|
||||
|
||||
### 2. 彻底撤销最近一次提交(丢弃所有修改)
|
||||
|
||||
|
||||
|
||||
这类似于 `git reset --hard HEAD~1` 的效果,会完全丢弃最近提交的所有修改。**请务必谨慎使用此选项,因为它会丢失数据!**
|
||||
|
||||
1. **打开日志/历史记录:** 同样,在 SourceTree 中打开“日志/历史”选项卡。
|
||||
2. **定位要撤销的提交:** 找到你想撤销的**前一个**提交。
|
||||
3. **右键点击并选择:** 右键点击该提交。
|
||||
4. **选择“将当前分支重置到此提交”:** 在弹出的菜单中选择 **“将当前分支重置到此提交”** (Reset current branch to this commit)。
|
||||
5. **选择重置模式:** 在弹窗中,选择 **“Hard(硬重置)”**。
|
||||
6. **确认:** 点击“确定”或“Reset”按钮。SourceTree 还会再次弹出警告,提醒你这将丢失数据,请确认。
|
||||
|
||||
执行此操作后,你的仓库状态会完全回溯到选定的提交,所有后续的修改和提交都将消失。
|
||||
|
||||
------
|
||||
|
||||
|
||||
|
||||
- **未推送的提交:** 上述操作主要用于**尚未推送到远程仓库**的本地提交。如果你已经将提交推送到远程,使用 `git reset` 会导致本地和远程历史不一致,从而引发问题。对于已推送的提交,通常应该使用 **“逆转提交”(Revert Commit)**,它会创建一个新的提交来撤销之前的修改,而不是改写历史。
|
||||
- **Revert(逆转)操作:** 如果你希望逆转某个已推送的提交,可以在 SourceTree 中右键点击该提交,然后选择 **“逆转提交 <哈希值>”** (Revert commit <hash>)。这会创建一个新的提交来撤销该提交的修改,并且不会改变历史,是更安全的选择。
|
||||
|
||||
|
After Width: | Height: | Size: 131 KiB |
|
After Width: | Height: | Size: 48 KiB |
|
After Width: | Height: | Size: 6.8 KiB |
|
After Width: | Height: | Size: 29 KiB |
|
After Width: | Height: | Size: 38 KiB |
|
After Width: | Height: | Size: 44 KiB |
|
After Width: | Height: | Size: 36 KiB |
|
After Width: | Height: | Size: 34 KiB |
@@ -257,3 +257,247 @@ docker images
|
||||
docker run --name xiaodaerpnetcore -p 7274:80 -d xiaodaerp/netcore
|
||||
```
|
||||
|
||||
# Jenkins环境配置
|
||||
|
||||
## Docker容器内安装NVM
|
||||
|
||||
首先以bash命令行交互形式进入容器
|
||||
|
||||
```shell
|
||||
docker exec -it jenkins /bin/bash
|
||||
```
|
||||
|
||||
下载并执行nvm-sh脚本
|
||||
|
||||
```shell
|
||||
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.3/install.sh | bash
|
||||
```
|
||||
|
||||
执行完成,需应用环境变量
|
||||
|
||||
```shell
|
||||
source ~/.bashrc
|
||||
```
|
||||
|
||||
全局安装pnpm
|
||||
|
||||
```shell
|
||||
npm install -g pnpm
|
||||
```
|
||||
|
||||
设置源
|
||||
|
||||
```shell
|
||||
pnpm config set registry https://registry.npmmirror.com
|
||||
```
|
||||
|
||||
查看nodejs位置
|
||||
|
||||
```shell
|
||||
npm prefix -g
|
||||
```
|
||||
|
||||
## Docker容器内安装JDK
|
||||
|
||||
首先下载好需要的jdk包
|
||||
|
||||
复制到容器内用户目录下
|
||||
|
||||
```shell
|
||||
docker cp docker cp ~/OpenJDK21U-jdk_aarch64_linux_hotspot_21.0.8_9.tar.gz jenkins:/root
|
||||
```
|
||||
|
||||
以交互模式进入到容器内
|
||||
|
||||
```shell
|
||||
docker exec -it jenkins /bin/bash
|
||||
```
|
||||
|
||||
解压压缩包
|
||||
|
||||
```shell
|
||||
cd ~
|
||||
tar -zxvf OpenJDK21U-jdk_aarch64_linux_hotspot_21.0.8_9.tar.gz
|
||||
```
|
||||
|
||||
# Jenkins Pipeline(流水线)
|
||||
|
||||
```shell
|
||||
pipeline {
|
||||
agent any
|
||||
|
||||
tools {
|
||||
nodejs 'NodeJS 22.17.0'
|
||||
}
|
||||
|
||||
environment {
|
||||
GIT_URL = 'http://192.168.6.20:9980/line-group/dify-conversation.git'
|
||||
BRANCH_NAME = 'erp-conversation'
|
||||
}
|
||||
|
||||
stages {
|
||||
stage('Preparation') {
|
||||
steps {
|
||||
// 清理工作空间
|
||||
// deleteDir()
|
||||
|
||||
// 拉取代码
|
||||
git branch: "${BRANCH_NAME}",
|
||||
url: "${GIT_URL}",
|
||||
credentialsId: '118322d7-1666-4f0b-b48b-349dcead864c',
|
||||
changelog: true,
|
||||
poll: false
|
||||
}
|
||||
}
|
||||
|
||||
stage('Setup Environment') {
|
||||
steps {
|
||||
sh '''
|
||||
node --version
|
||||
pnpm --version
|
||||
'''
|
||||
}
|
||||
}
|
||||
|
||||
stage('Intall Dependencies') {
|
||||
steps {
|
||||
sh '''
|
||||
# 清理缓存
|
||||
pnpm store prune || true
|
||||
|
||||
# 安装依赖
|
||||
pnpm install --frozen-lockfile
|
||||
|
||||
# 检查依赖
|
||||
pnpm list --depth 0
|
||||
'''
|
||||
}
|
||||
}
|
||||
|
||||
stage('Build Production') {
|
||||
steps {
|
||||
sh '''
|
||||
# 清理旧构建
|
||||
rm -rf .next || true
|
||||
|
||||
# 生产环境构建
|
||||
pnpm run build
|
||||
|
||||
# 验证构建结果
|
||||
if [ -d ".next" ]; then
|
||||
echo "构建成功,文件列表:"
|
||||
ls -la .next/
|
||||
echo "总文件数:$(find dist -type f | wc -l)"
|
||||
else
|
||||
echo "构建失败,.next目录不存在"
|
||||
exit 1
|
||||
fi
|
||||
'''
|
||||
}
|
||||
|
||||
post {
|
||||
success {
|
||||
archiveArtifacts artifacts: '.next/**/*', fingerprint: true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
stage('Quality Check') {
|
||||
steps {
|
||||
sh '''
|
||||
# 代码检查
|
||||
pnpm run lint --no-fix || echo "代码检查完成"
|
||||
|
||||
# 类型检查
|
||||
pnpm run type-check || echo "类型检查完成"
|
||||
'''
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
post {
|
||||
cleanup {
|
||||
cleanWs()
|
||||
}
|
||||
success {
|
||||
echo 'Pipeline completed successfully!'
|
||||
}
|
||||
failure {
|
||||
echo 'Pipeline failed!'
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
# Jenkins Node(节点)
|
||||
|
||||
## 创建 Windows 服务
|
||||
|
||||
使用 **WinSW (Windows Service Wrapper)**
|
||||
|
||||
### 1. 下载 WinSW
|
||||
|
||||
- 请访问 WinSW 的官方发布页面: https://github.com/winsw/winsw/releases
|
||||
- 下载最新的 `.exe` 文件。鉴于是 Windows 服务器,请下载 **`WinSW-x64.exe`**。(如果系统是 32 位的,才下载 `WinSW-x86.exe`)。
|
||||
|
||||
### 2. 准备文件
|
||||
|
||||
1. 将下载的 `WinSW-x64.exe` 文件复制到工作目录:`D:\common_components\jenkins-agent`。
|
||||
2. **(关键)重命名:** 在该目录中,将 `WinSW-x64.exe` 重命名为 `jenkins-agent-admin.exe`。(这个名字可以自定,但 `.xml` 必须同名)
|
||||
3. 确保从 Jenkins 下载的 `agent.jar` 文件也在此目录中。
|
||||
|
||||
现在,`D:\common_components\jenkins-agent` 文件夹中**至少**应该有这两个文件:
|
||||
|
||||
- `jenkins-agent-admin.exe`
|
||||
- `agent.jar`
|
||||
|
||||
### 3. 创建 XML 配置文件
|
||||
|
||||
1. 在**同一目录** (`D:\common_components\jenkins-agent`) 中,创建一个**新的文本文件**。
|
||||
|
||||
2. 将这个新文件重命名为 **`jenkins-agent-admin.xml`**。(**注意:** 它的名字必须和 `.exe` 文件的名字完全一样,只是扩展名不同)。
|
||||
|
||||
3. 用记事本或任何文本编辑器打开 `jenkins-agent-admin.xml`,然后将**以下所有内容**完整地复制并粘贴进去:
|
||||
```xml
|
||||
<service>
|
||||
<id>jenkins-agent-admin</id>
|
||||
|
||||
<name>Jenkins Agent (Admin)</name>
|
||||
|
||||
<description>此服务以管理员权限运行 Jenkins JNLP 代理。</description>
|
||||
|
||||
<executable>java</executable>
|
||||
|
||||
<arguments>-jar "%BASE%\agent.jar" -jnlpUrl http://192.168.6.1:23123/computer/windows%2Dadmin%2Dagent/jenkins-agent.jnlp -secret *********84158aed83c119f8f53b579db8a315a4e9bda61687cbdd088e***7 -workDir "D:\common_components\jenkins-agent"</arguments>
|
||||
|
||||
<workingdirectory>D:\common_components\jenkins-agent</workingdirectory>
|
||||
|
||||
<log mode="rotate"/>
|
||||
</service>
|
||||
```
|
||||
|
||||
### 4. 安装服务
|
||||
|
||||
1. 再次打开一个**管理员**命令提示符 (cmd)。
|
||||
|
||||
2. `cd` 到工作目录:
|
||||
|
||||
```cmd
|
||||
D:
|
||||
cd D:\common_components\jenkins-agent
|
||||
```
|
||||
|
||||
3. 运行重命名的 `.exe` 文件,并附带 `install` 命令:
|
||||
```cmd
|
||||
jenkins-agent-admin.exe install
|
||||
```
|
||||
|
||||
### 5. 设置登录帐户
|
||||
|
||||
这是**必须**的步骤,和之前一样:
|
||||
|
||||
1. 打开 "服务" (`services.msc`)。
|
||||
2. 找到新安装的服务,名字是 **"Jenkins Agent (Admin)"**(这是在 `.xml` 中设置的)。
|
||||
3. 右键点击 -> **"属性"** -> **"登录"** 选项卡。
|
||||
4. 选择 **"此帐户"**,并输入**Windows 管理员用户名和密码**。
|
||||
5. 点击 "应用" -> "确定"
|
||||
|
||||
@@ -140,6 +140,10 @@ tar -zxvf:解压(最常用)
|
||||
tar -zxvf wwwroot.tar.gz
|
||||
```
|
||||
|
||||
tar.gz 和 tgz 的区别
|
||||
|
||||
tar.gz 和 tgz 是两种常见的压缩文件格式,它们在本质上是相同的,只是文件扩展名不同。两者都是通过 tar 命令将多个文件打包成一个文件,然后再使用 gzip 压缩工具进行压缩。
|
||||
|
||||
### 系统服务:
|
||||
|
||||
systemstl:操作系统服务。
|
||||
@@ -439,6 +443,110 @@ chmod u-w /etc/sudoers
|
||||
|
||||
这样普通用户就可以使用sudo了.
|
||||
|
||||
### 修改目录权限
|
||||
|
||||
**查看当前目录权限**
|
||||
|
||||
```bash
|
||||
sudo ls -ld /OLAP
|
||||
```
|
||||
|
||||
输出实例:
|
||||
|
||||
`drwxr-xr-x 5 root root 4096 Aug 5 08:27 /OLAP`
|
||||
|
||||
**修改目录权限**
|
||||
|
||||
使当前用户(假设为 `user`)能够对 `/OLAP`目录进行读写操作,可以将目录权限修改为`775`(即`rwxrwxr-x`):
|
||||
|
||||
```bash
|
||||
sudo chmod 775 /OLAP
|
||||
```
|
||||
|
||||
这样,目录的所有者和所属组的用户都可以读写该目录,其他用户则由读取和执行权限。
|
||||
|
||||
**将当前用户加入目录所属组**
|
||||
|
||||
如果目录所属组是`root`,可以将当前用户`user`加入`root`组(不推荐,因为`root`组权限过高):
|
||||
|
||||
```bash
|
||||
sudo usermod -aG root user
|
||||
```
|
||||
|
||||
然后,重新登录或重启系统以使组变更生效。
|
||||
|
||||
### 更改目录的所有者
|
||||
|
||||
**查看当前目录的所有者**
|
||||
|
||||
查看`/OLAP`目录的当前所有者:
|
||||
|
||||
```bash
|
||||
sudo ls -ld /OLAP
|
||||
```
|
||||
|
||||
**更改目录的所有者**
|
||||
|
||||
将`/OLAP`目录的所有者更改为当前用户(假设为`user`):
|
||||
|
||||
```bash
|
||||
sudo chown user:user /OLAP
|
||||
```
|
||||
|
||||
这样,当前用户将拥有对该目录的完全控制权。
|
||||
|
||||
### 使用 ACL(访问控制列表)
|
||||
|
||||
> ACL 提供了更细粒度的权限控制,允许为特定用户或组设置特定权限。
|
||||
|
||||
**安装 ACL 工具**
|
||||
|
||||
在某些系统中,ACL 工具可能未默认安装,可以通过以下命令安装:
|
||||
|
||||
```bash
|
||||
sudo apt install acl -y
|
||||
sudo dnf insyall acl -y
|
||||
```
|
||||
|
||||
**设置 ACL 权限**
|
||||
|
||||
为当前用户(假设为`user`)设置读写权限:
|
||||
|
||||
```bash
|
||||
sudo setfacl -m u:user:rwx /OLAP
|
||||
```
|
||||
|
||||
这样,`user`用户将获得对`/OLAP`目录的读写权限,而不会影响其他用户的权限。
|
||||
|
||||
**验证 ACL 权限**
|
||||
|
||||
查看当前目录的 ACL 权限:
|
||||
|
||||
```bash
|
||||
getfacl /OLAP
|
||||
```
|
||||
|
||||
输出实例:
|
||||
```
|
||||
getfacl: Removing leading '/' from absolute path names
|
||||
# file: OLAP
|
||||
# owner: user
|
||||
# group: user
|
||||
user::rwx
|
||||
group::r-x
|
||||
other::r-x
|
||||
```
|
||||
|
||||
### 更改目录的默认权限(可选)
|
||||
|
||||
如果要将新创建的文件和子目录自动继承特定权限,可以设置默认 ACL:
|
||||
|
||||
```bash
|
||||
sudo setfacl -dm u:user:rwx /OLAP
|
||||
```
|
||||
|
||||
这样,新创建的文件和子目录将自动继承 `user` 用户的读写权限。
|
||||
|
||||
## Shell 脚本
|
||||
|
||||
### 为什么大多数 shell 脚本都包含 #! /bin/bash 在 shell 脚本的开头?
|
||||
@@ -1308,9 +1416,9 @@ UUID=0EAB-5879 /boot/efi vfat umask=0077,shortname=win
|
||||
systemctl daemon-reload
|
||||
```
|
||||
|
||||
## 挂载远程卷
|
||||
## 挂载卷
|
||||
|
||||
### Windows
|
||||
### Windows 网络共享位置
|
||||
|
||||
首先创建本地的挂载目录,一般在`/mnt`下
|
||||
|
||||
@@ -1332,6 +1440,82 @@ dnf install -y cifs-utils
|
||||
mount -t cifs -o username=user,password=backup //192.168.0.1/备份 /mnt/wdshare/
|
||||
```
|
||||
|
||||
以上为暂时挂载,还需要永久挂载,避免系统重启后挂载丢失
|
||||
|
||||
编辑`/etc/fstab`配置文件,在最后一行添加以下配置
|
||||
|
||||
```shell
|
||||
//192.168.0.1/备份 /mnt/wdshare/ cifs username=user,password=backup 0 0
|
||||
```
|
||||
|
||||
### NTFS 分区
|
||||
|
||||
#### 可读可写
|
||||
|
||||
**识别NTFS分区**
|
||||
|
||||
```shell
|
||||
sudo parted -l
|
||||
```
|
||||
|
||||

|
||||
|
||||
**创建挂载点**:使用*mkdir*命令创建一个挂载点
|
||||
|
||||
```shell
|
||||
sudo mkdir /mnt/ntfs1
|
||||
```
|
||||
|
||||
**安装依赖**:更新包仓库并安装*fuse*和*ntfs-3g*
|
||||
|
||||
```shell
|
||||
sudo apt update
|
||||
sudo apt install fuse -y
|
||||
sudo apt install ntfs-3g -y
|
||||
```
|
||||
|
||||
**挂载分区**:使用*mount*命令挂载分区
|
||||
|
||||
```shell
|
||||
sudo mount -t ntfs-3g /dev/sda1 /mnt/ntfs1/
|
||||
```
|
||||
|
||||
> 其中 /dev/sda1 就是由上述命令的 sudo parted -l 得来的,Disk /dev/sda: 1000GB ,这行标识出了 设备的路径,Disk Flags: 及下述表格的列 Number 则标识出了具体的 设备号,也可通过这个命令进行验证 `sudo blkid /dev/sda1`
|
||||
>
|
||||
> 
|
||||
>
|
||||
> 可以看到 `TYPE="ntfs"`字样
|
||||
|
||||
**验证挂载**:使用*df*命令检查所有文件系统的详细信息,验证分区是否成功挂载
|
||||
|
||||
```shell
|
||||
df -Th
|
||||
```
|
||||
|
||||

|
||||
|
||||
可以看到最后一行的就是刚刚挂载上的设备卷
|
||||
|
||||
这个只是临时挂载,还需要编辑`/etc/fstab`配置文件,防止系统重启后,还需再手动挂载
|
||||
|
||||
```shell
|
||||
sudo vim /etc/fstab
|
||||
```
|
||||
|
||||
在最后一行下面添加这一行
|
||||
|
||||
```shell
|
||||
/dev/sda1 /mnt/ntfs1 fuseblk defaults 0 0
|
||||
```
|
||||
|
||||
`:wq`保存好,使用以下命令使修改生效
|
||||
|
||||
```shell
|
||||
sudo systemctl daemon-reload
|
||||
```
|
||||
|
||||
|
||||
|
||||
## 分配Swap
|
||||
|
||||
查看分区大小
|
||||
@@ -2134,6 +2318,19 @@ fc-cache -f -v
|
||||
|
||||
#### 安装
|
||||
|
||||
进入控制面板中的 程序和功能 页面
|
||||
|
||||
用组合键 Win + R 启动运行窗口 `appwiz.cpl` 回车
|
||||
|
||||
启用或关闭 Windows 功能,勾选适用于 Linux 的 Windows 子系统
|
||||
|
||||

|
||||
|
||||
也可解决安装发行版时的报错问题
|
||||
|
||||
由于未安装所需的特性,无法启动操作。
|
||||
错误代码: Wsl/InstallDistro/Service/RegisterDistro/CreateVm/HCS/HCS_E_SERVICE_NOT_AVAILABLE
|
||||
|
||||
```powershell
|
||||
wsl --install
|
||||
```
|
||||
@@ -2150,6 +2347,45 @@ wsl --install -d <Distribution Name>
|
||||
|
||||
/mnt目录下是Windows系统的挂载盘,可直接访问Windows磁盘文件
|
||||
|
||||
#### 迁移
|
||||
|
||||
```powershell
|
||||
wsl --manage Ubuntu-24.04 --move d:\ubuntu
|
||||
```
|
||||
|
||||
#### 导出
|
||||
|
||||
**查看当前 WSL 分发版**
|
||||
|
||||
```powershell
|
||||
wsl -l
|
||||
```
|
||||
|
||||
输出示例:
|
||||
|
||||
```powershell
|
||||
适用于 Linux 的 Windows 子系统分发:
|
||||
archlinux (默认值)
|
||||
```
|
||||
|
||||
**停止运行中的 WSL**
|
||||
|
||||
```powershell
|
||||
wsl --terminate archlinux
|
||||
```
|
||||
|
||||
**导出镜像**
|
||||
|
||||
使用 *wsl --export* 命令将分发版导出为 *.tar* 文件:
|
||||
|
||||
```powershell
|
||||
wsl --export archlinux E:\Backup\archlinux.tar
|
||||
```
|
||||
|
||||
#### 导入
|
||||
|
||||
|
||||
|
||||
#### 通过FinalShell连接WSL2
|
||||
|
||||
##### 方式1
|
||||
@@ -2458,6 +2694,16 @@ dnf install neofetch
|
||||
neofetch
|
||||
```
|
||||
|
||||
## 安装 Fastfetch
|
||||
|
||||
```bash
|
||||
dnf update -y
|
||||
wget https://github.com/fastfetch-cli/fastfetch/releases/download/2.49.0/fastfetch-linux-amd64.rpm -O fastfetch.rpm
|
||||
dnf install -y fastfetch.rpm
|
||||
```
|
||||
|
||||
|
||||
|
||||
## 安装 Screenfetch
|
||||
|
||||
```shell
|
||||
@@ -2677,6 +2923,87 @@ git clone --depth=1 https://gitee.com/romkatv/powerlevel10k.git ${ZSH_CUSTOM:-$H
|
||||
|
||||
在 `~/.zshrc` 设置 `ZSH_THEME="powerlevel10k/powerlevel10k"`。接下来,终端会自动引导你配置 `powerlevel10k`,若已配置可输入`p10k configure`重新进行配置引导。
|
||||
|
||||
若是安装的AlmaLinux minimal系统,需先通过`dnf`安装 `"Development Tools"`,再执行`source ~/.zshrc`
|
||||
|
||||
```bash
|
||||
dnf groupinstall "Development Tools" -y
|
||||
```
|
||||
|
||||
#### robbyrussell
|
||||
|
||||
显示路径每一级的首字母和最后一级目录的全名
|
||||
|
||||
默认主题只显示路径最后一级名字,其他的一些主题可能显示完整路径,但那太长了。我只发现主题 fishy 是这样显示的,这也和 fish 命令行相同。
|
||||
|
||||
配置
|
||||
|
||||
```shell
|
||||
vim ~/.oh-my-zsh/themes/robbyrussell.zsh-theme
|
||||
```
|
||||
|
||||
添加一个函数
|
||||
|
||||
```shell
|
||||
_fishy_collapsed_wd() {
|
||||
local i pwd
|
||||
pwd=("${(s:/:)PWD/#$HOME/~}")
|
||||
if (( $#pwd > 1 )); then
|
||||
for i in {1..$(($#pwd-1))}; do
|
||||
if [[ "$pwd[$i]" = .* ]]; then
|
||||
pwd[$i]="${${pwd[$i]}[1,2]}"
|
||||
else
|
||||
pwd[$i]="${${pwd[$i]}[1]}"
|
||||
fi
|
||||
done
|
||||
fi
|
||||
echo "${(j:/:)pwd}"
|
||||
}
|
||||
```
|
||||
|
||||
在 PROMPT 那一行,把表示目录的 `%c` (其他主题可能是 `%C`,`%~` ,`%2` 等)改成 `$(_fishy_collapsed_wd)`,重启 zsh 即可。
|
||||
|
||||
显示用户
|
||||
|
||||
在 PROMPT 前适当加上 `%{$fg_bold[blue]%}${USER}` 即可。左边的是在设置颜色。
|
||||
|
||||
显示上一条命令返回值
|
||||
|
||||
这个默认主题,当返回值为 0 时箭头为绿色,非 0 时为红色,我想让他非 0 时显示返回值。
|
||||
|
||||
解决方案:PROMPT 适当位置加上 `%?`,记得不要写成 `$?` 因为后者只显示第一个数字(好像是这样,我没仔细查过)。
|
||||
|
||||
最终配置
|
||||
|
||||
```shell
|
||||
if [ `id -u` -eq 0 ];then
|
||||
PROMPT="%(?:%{$fg_bold[red]%}root %{$fg_bold[green]%}➜ :%{$fg_bold[red]%}root %{$fg_bold[red]%}%? ➜ )"
|
||||
else
|
||||
PROMPT="%(?:%{$fg_bold[blue]%}${USER} %{$fg_bold[green]%}➜ :%{$fg_bold[blue]%}${USER} %{$fg_bold[red]%}%? ➜ )"
|
||||
fi
|
||||
|
||||
_fishy_collapsed_wd() {
|
||||
local i pwd
|
||||
pwd=("${(s:/:)PWD/#$HOME/~}")
|
||||
if (( $#pwd > 1 )); then
|
||||
for i in {1..$(($#pwd-1))}; do
|
||||
if [[ "$pwd[$i]" = .* ]]; then
|
||||
pwd[$i]="${${pwd[$i]}[1,2]}"
|
||||
else
|
||||
pwd[$i]="${${pwd[$i]}[1]}"
|
||||
fi
|
||||
done
|
||||
fi
|
||||
echo "${(j:/:)pwd}"
|
||||
}
|
||||
PROMPT+=' %{$fg[yellow]%}$(_fishy_collapsed_wd)%{$reset_color%} $(git_prompt_info)'
|
||||
|
||||
|
||||
ZSH_THEME_GIT_PROMPT_PREFIX="%{$fg[blue]%}git:(%{$fg[yellow]%}"
|
||||
ZSH_THEME_GIT_PROMPT_SUFFIX="%{$reset_color%} "
|
||||
ZSH_THEME_GIT_PROMPT_DIRTY="%{$fg[blue]%}) %{$fg[yellow]%}✗"
|
||||
ZSH_THEME_GIT_PROMPT_CLEAN="%{$fg[blue]%})"
|
||||
```
|
||||
|
||||
### 插件
|
||||
|
||||
> `oh-my-zsh` 已经内置了 `git` 插件,内置插件可以在 `~/.oh-my-zsh/plugins` 中查看,下面介绍一下我常用的插件,更多插件可以在 [awesome-zsh-plugins](https://github.com/unixorn/awesome-zsh-plugins) 里查看。
|
||||
@@ -2762,7 +3089,7 @@ Are you sure you want to remove Oh My Zsh? [y/N] Y
|
||||
upgrade_oh_my_zsh
|
||||
```
|
||||
|
||||
安装Nerd Fonts
|
||||
### 安装Nerd Fonts
|
||||
|
||||
```shell
|
||||
unzip nerd-fonts.zip
|
||||
@@ -2905,6 +3232,8 @@ sudo systemctl status jenkins
|
||||
|
||||
### 修改端口
|
||||
|
||||
修改为想要的端口
|
||||
|
||||
```shell
|
||||
# 进入目录
|
||||
cd /usr/lib/systemd/system
|
||||
@@ -2912,8 +3241,11 @@ vim jenkins.service
|
||||
# 或者
|
||||
vim /usr/lib/systemd/system/jenkins.service
|
||||
|
||||
# 修改为想要的端口
|
||||
Environment="JENKINS_PORT=8889"
|
||||
# Port to listen on for HTTP requests. Set to -1 to disable.
|
||||
# To be able to listen on privileged ports (port numbers less than 1024),
|
||||
# add the CAP_NET_BIND_SERVICE capability to the AmbientCapabilities
|
||||
# directive below.
|
||||
Environment="JENKINS_PORT=16060"
|
||||
|
||||
# 重新加载配置文件
|
||||
systemctl daemon-reload
|
||||
@@ -2922,6 +3254,8 @@ systemctl daemon-reload
|
||||
|
||||
### 修改用户及用户组
|
||||
|
||||
修改为root
|
||||
|
||||
```shell
|
||||
# 进入目录
|
||||
cd /usr/lib/systemd/system
|
||||
@@ -2929,7 +3263,11 @@ vim jenkins.service
|
||||
# 或者
|
||||
vim /usr/lib/systemd/system/jenkins.service
|
||||
|
||||
# 修改为root
|
||||
|
||||
# Unix account that runs the Jenkins daemon
|
||||
# Be careful when you change this, as you need to update the permissions of
|
||||
# $JENKINS_HOME, $JENKINS_LOG, and (if you have already run Jenkins)
|
||||
# $JENKINS_WEBROOT.
|
||||
User=root
|
||||
Group=root
|
||||
|
||||
@@ -2939,6 +3277,8 @@ systemctl daemon-reload
|
||||
|
||||
### 解决Jenkins部分汉化、汉化不全有效办法
|
||||
|
||||
添加 -Duser.language=C.UTF-8
|
||||
|
||||
```shell
|
||||
# 进入目录
|
||||
cd /usr/lib/systemd/system
|
||||
@@ -2946,13 +3286,49 @@ vim jenkins.service
|
||||
# 或者
|
||||
vim /usr/lib/systemd/system/jenkins.service
|
||||
|
||||
# 添加 -Duser.language=C.UTF-8
|
||||
# Arguments for the Jenkins JVM
|
||||
Environment="JAVA_OPTS=-Djava.awt.headless=true -Duser.language=C.UTF-8"
|
||||
|
||||
# 重新加载配置文件
|
||||
systemctl daemon-reload
|
||||
```
|
||||
|
||||
### 解决 Jenkins 无法拉取TLS 1.0的老旧SVN项目
|
||||
|
||||
主要是Java JDK禁用了TLS 1.0协议,需修改`java.security`配置文件进行开启
|
||||
|
||||
首先找到启动Jenkins的Java JDK的目录,找到`conf/`
|
||||
|
||||
使用`vim`进行编辑查看,可以看到如下有 TLSv1, TLSv1.1,3DES_EDE_CBC,编辑将其删除
|
||||
|
||||
```yaml
|
||||
# Example:
|
||||
# jdk.tls.disabledAlgorithms=MD5, SSLv3, DSA, RSA keySize < 2048, \
|
||||
# rsa_pkcs1_sha1, secp224r1
|
||||
jdk.tls.disabledAlgorithms=SSLv3, TLSv1, TLSv1.1, DTLSv1.0, RC4, DES, \
|
||||
MD5withRSA, DH keySize < 1024, EC keySize < 224, 3DES_EDE_CBC, anon, NULL, \
|
||||
ECDH
|
||||
|
||||
```
|
||||
|
||||
`:wq`保存即可。
|
||||
|
||||
### 升级
|
||||
|
||||
#### AlmaLinux
|
||||
|
||||
升级前请先备份上述 `jenkins.service` 配置文件
|
||||
|
||||
```bash
|
||||
cp -r /usr/lib/systemd/system/jenkins.service /usr/lib/systemd/system/jenkins.service.bak
|
||||
```
|
||||
|
||||
使用dnf包管理器进行升级
|
||||
|
||||
```bash
|
||||
dnf upgrade jenkins
|
||||
```
|
||||
|
||||
## 安装 Certbot
|
||||
|
||||
**Certbot** 是由 **Electronic Frontier Foundation (EFF)** 提供的一个开源命令行工具,用于自动化从 Let’s Encrypt 获取和管理 SSL 证书。Certbot 会自动为你处理证书申请、安装和续期等过程。,用于自动化整个 SSL 证书的管理流程。它可以做以下几件事:
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
---
|
||||
title: Maven
|
||||
date: 2025-11-06 10:15:58
|
||||
tags:
|
||||
---
|
||||
|
||||
# 命令
|
||||
|
||||
## mvn package
|
||||
|
||||
|
||||
|
||||
## mvn install
|
||||
|
||||
@@ -969,3 +969,43 @@ Maven下载依赖
|
||||
|
||||
仅用于分表。仅DATE、DATETIME类型。
|
||||
一年之中第几天%分表数。tbpartitions不能超过366。
|
||||
|
||||
# MySQL 查询语句
|
||||
|
||||
## 查询语句中字段别名取表中的comment
|
||||
|
||||
在 MySQL 中,字段的 comment 并不存储在数据行里,而是放在 **information_schema.COLUMNS** 中。
|
||||
因此可以通过把 **column_comment** 查出来,再拼成 **SELECT 语句的别名**,实现“用表中字段的 comment 做别名”的效果。
|
||||
|
||||
一次性查出某张表所有列,并把 comment 作为别名:
|
||||
|
||||
```mysql
|
||||
-- 示例:表名 mydb.mytable
|
||||
SELECT CONCAT(
|
||||
'SELECT ',
|
||||
GROUP_CONCAT(
|
||||
CONCAT('`', COLUMN_NAME, '` AS `', REPLACE(COLUMN_COMMENT, '`', ''), '`')
|
||||
ORDER BY ORDINAL_POSITION
|
||||
),
|
||||
' FROM mytable;'
|
||||
) AS sql_text
|
||||
FROM information_schema.COLUMNS
|
||||
WHERE TABLE_SCHEMA = 'mydb'
|
||||
AND TABLE_NAME = 'mytable';
|
||||
```
|
||||
|
||||
执行后得到一条 SQL,例如:
|
||||
|
||||
```mysql
|
||||
SELECT id AS 主键, name AS 用户名, age AS 年龄 FROM mytable;
|
||||
```
|
||||
|
||||
**拼 SQL 时丢列**
|
||||
上一段拼接脚本里 `GROUP_CONCAT` 有 **长度限制**(默认 1024 字节)。
|
||||
如果表列很多,会被截断导致看起来“少字段”。
|
||||
解决方法:
|
||||
|
||||
```mysql
|
||||
SET SESSION group_concat_max_len = 1000000; -- 临时放大
|
||||
```
|
||||
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
---
|
||||
title: .NET
|
||||
date: 2025-07-22 10:32:51
|
||||
tags:
|
||||
---
|
||||
|
||||
# Nuget包管理器
|
||||
|
||||
## 无法联网的情况下导入包
|
||||
|
||||
### 使用本地文件夹作为 NuGet 源
|
||||
|
||||
#### 步骤 1:准备本地 NuGet 包
|
||||
|
||||
你需要提前从能联网的机器上下载所需的 `.nupkg` 文件。
|
||||
|
||||
使用命令行下载:
|
||||
|
||||
```powershell
|
||||
.\nuget.exe install MathNet.Numerics -OutputDirectory D:\NuGetOfflinePackages -Version 5.0.0
|
||||
```
|
||||
|
||||
这会下载包及其依赖到 `D:\NuGetOfflinePackages` 目录。
|
||||
|
||||
> ⚠️ 注意:有些包有多个依赖项,需要把所有 `.nupkg` 都拷贝过来。
|
||||
|
||||
#### 步骤 2:将包复制到离线机器的某个目录
|
||||
|
||||
比如:
|
||||
|
||||
```
|
||||
D:\NuGetOfflinePackages\
|
||||
├── Newtonsoft.Json.13.0.3.nupkg
|
||||
├── System.Net.Http.4.3.4.nupkg
|
||||
└── ...
|
||||
```
|
||||
|
||||
#### 步骤 3:配置 Visual Studio 使用本地包源
|
||||
|
||||
1. 打开 Visual Studio。
|
||||
|
||||
2. 进入:**工具 (Tools) → NuGet 包管理器 → 程序包管理器设置** 。
|
||||
|
||||
3. 左侧选择 **NuGet 包管理器 → 程序包源** 。
|
||||
|
||||
4. 点击
|
||||
|
||||
\+
|
||||
|
||||
添加新的源:
|
||||
|
||||
- 名称:比如 `Local Packages`
|
||||
- 源:填写你的文件夹路径,如 `D:\NuGetOfflinePackages`
|
||||
|
||||
5. 点击 **更新** ,然后确定。
|
||||
|
||||
✅ 完成后,在“管理 NuGet 包”时就可以看到并安装本地包了。
|
||||
|
||||
@@ -286,6 +286,74 @@ export NLS_LANG="AMERICAN_AMERICA.AL32UTF8"
|
||||
|
||||
### 登录
|
||||
|
||||
#### 使用操作系统认证
|
||||
|
||||
适用于以管理员身份登录数据库:
|
||||
|
||||
```bash
|
||||
sqlplus / as sysdba
|
||||
```
|
||||
|
||||
- */* 表示操作系统认证。
|
||||
- *as sysdba* 用于以管理员权限登录。
|
||||
|
||||
#### 使用用户名和密码登录
|
||||
|
||||
通过提供用户名、密码和数据库连接信息:
|
||||
|
||||
```bash
|
||||
sqlplus username/password@hostname:port/SID
|
||||
```
|
||||
|
||||
**示例:**
|
||||
|
||||
```bash
|
||||
sqlplus scott/tiger@192.168.1.100:1521/orcl
|
||||
```
|
||||
|
||||
- *hostname* 是数据库主机名或 IP 地址。
|
||||
- *port* 是监听端口,默认是 *1521*。
|
||||
- *SID* 是数据库实例名。
|
||||
|
||||
如果已配置 TNS,则可以简化为:
|
||||
|
||||
```bash
|
||||
sqlplus username/password@TNSNAME
|
||||
```
|
||||
|
||||
#### 无日志模式登录
|
||||
|
||||
先启动 SQL*Plus,再手动连接数据库:
|
||||
|
||||
```bash
|
||||
sqlplus /nolog
|
||||
```
|
||||
|
||||
然后使用以下命令连接:
|
||||
|
||||
```bash
|
||||
conn username/password@hostname:port/SID
|
||||
```
|
||||
|
||||
**优点:** 避免直接暴露用户名和密码。
|
||||
|
||||
#### 直接交互式登录
|
||||
|
||||
直接输入 *sqlplus*,按提示输入用户名和密码:
|
||||
|
||||
```bash
|
||||
sqlplus
|
||||
```
|
||||
|
||||
**示例:**
|
||||
|
||||
```
|
||||
请输入用户名: scott
|
||||
输入口令: tiger
|
||||
```
|
||||
|
||||
|
||||
|
||||
```shell
|
||||
# 以oracle账号登录
|
||||
su oracle
|
||||
@@ -304,7 +372,7 @@ alter user sys identified by 123456;
|
||||
|
||||
## CDB 和 PDB
|
||||
|
||||

|
||||

|
||||
|
||||
- CDB :容器数据库,名称为 CDB$ROOT。其作用就是系统数据库,sys账号等以及Common User(公共用户)都保存在里面。同时它可以管理PDB数据库
|
||||
|
||||
|
||||
@@ -60,3 +60,152 @@ set-alias -name sudo -value _sudo
|
||||
```text
|
||||
set-ExecutionPolicy RemoteSigned
|
||||
```
|
||||
|
||||
# 实用脚本
|
||||
|
||||
## 自动延长VS社区版过期时间
|
||||
|
||||
> 该脚本作用为 自动检查VS社区版是否在一天内过期,如是则自动延长30天
|
||||
>
|
||||
> 需事先从Github上Clone开源项目[beatcracker/VSCELicense: PowerShell module to get and set Visual Studio Community Edition license expiration date in registry (github.com)](https://github.com/beatcracker/VSCELicense)
|
||||
>
|
||||
> 然后放置在指定目录,并解除脚本执行限制,以管理员身份执行如下命令:
|
||||
>
|
||||
> ```powershell
|
||||
> Set-ExecutionPolicy RemoteSigned
|
||||
> ```
|
||||
>
|
||||
> 输入 A 即可
|
||||
|
||||
```powershell
|
||||
# 加载 VSCELicense 模块
|
||||
try {
|
||||
Import-Module -Name 'C:\VSCELicense\VSCELicense.psd1' -ErrorAction Stop
|
||||
} catch {
|
||||
Write-Error "无法加载模块 'C:\VSCELicense\VSCELicense.psd1',请确认路径是否正确。错误信息: $_"
|
||||
exit 1
|
||||
}
|
||||
|
||||
|
||||
# 获取许可证信息
|
||||
try {
|
||||
$output = Get-VSCELicenseExpirationDate -ErrorAction Stop | Out-String
|
||||
} catch {
|
||||
Write-Error "执行 Get-VSCELicenseExpirationDate 时出错: $_"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# 使用正则表达式提取版本号和过期日期
|
||||
$version = $null
|
||||
$expDateStr = $null
|
||||
|
||||
if ($output -match '(?m)^\s*(\d{4})\s+(\d{2}/\d{2}/\d{4}\s+\d{2}:\d{2}:\d{2})') {
|
||||
$version = $matches[1].Trim()
|
||||
$expDateStr = $matches[2].Trim()
|
||||
Write-Host "找到版本: $version"
|
||||
Write-Host "过期日期: $expDateStr"
|
||||
} else {
|
||||
Write-Error "无法从输出中找到版本和过期日期"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# 将过期日期字符串解析为 DateTime 对象
|
||||
try {
|
||||
$expirationDate = [datetime]::ParseExact($expDateStr, 'dd/MM/yyyy HH:mm:ss', $null)
|
||||
} catch {
|
||||
Write-Error "日期格式解析失败: $expDateStr. 错误: $_"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# 获取当前时间并设置阈值
|
||||
$currentTime = Get-Date
|
||||
$threshold = $currentTime.AddDays(1)
|
||||
|
||||
Write-Host "当前时间: $currentTime"
|
||||
Write-Host "过期时间: $expirationDate"
|
||||
Write-Host "阈值时间(当前时间 + 1天): $threshold"
|
||||
|
||||
# 判断是否在1天内过期 -le 表示小于等于 想起了 Mybatis-Plus 条件构造器中的 le
|
||||
if ($expirationDate -le $threshold) {
|
||||
Write-Host "许可证即将过期,正在执行 Set-VSCELicenseExpirationDate 命令..."
|
||||
try {
|
||||
Set-VSCELicenseExpirationDate -Version $version -ErrorAction Stop
|
||||
Write-Host "Set-VSCELicenseExpirationDate 命令执行成功。"
|
||||
} catch {
|
||||
Write-Error "执行 Set-VSCELicenseExpirationDate 时出错: $_"
|
||||
exit 1
|
||||
}
|
||||
} else {
|
||||
Write-Host "许可证未在一天内过期,无需操作。"
|
||||
}
|
||||
```
|
||||
|
||||
输出如下:
|
||||
|
||||

|
||||
|
||||
可结合任务计划程序进行使用,免去手动执行的烦恼
|
||||
|
||||

|
||||
|
||||
### 🧩 步骤 1:打开任务计划程序
|
||||
|
||||
1. 按下 `Win + R`,输入 `taskschd.msc`,回车。
|
||||
2. 在左侧的“任务计划程序库”中,右键选择“创建任务”。
|
||||
|
||||
### 🧩 步骤 2:设置任务基本信息
|
||||
|
||||
- 常规
|
||||
|
||||
选项卡:
|
||||
|
||||
- 名称:例如 `Check-VS-LicenseExpiration`
|
||||
- 描述(可选):每天早上 7 点检查许可证过期状态
|
||||
- 勾选“不管用户是否登录都要运行”
|
||||
- 勾选“使用最高权限”
|
||||
|
||||

|
||||
|
||||
### 🧩 步骤 3:设置触发器
|
||||
|
||||
1. 切换到 **触发器** 选项卡。
|
||||
2. 点击 **新建** 。
|
||||
3. 设置:
|
||||
- 开始时间:`07:00:00`
|
||||
- 每天
|
||||
- 勾选“启用此触发器”
|
||||
4. 点击 **确定** 。
|
||||
|
||||

|
||||
|
||||
### 🧩 步骤 4:设置操作
|
||||
|
||||
1. 切换到 **操作** 选项卡。
|
||||
2. 点击 **新建** 。
|
||||
3. 设置:
|
||||
- 操作:`启动程序`
|
||||
- 程序/脚本:`powershell.exe`
|
||||
- 参数(可选):`-ExecutionPolicy RemoteSigned -File "C:\VSCELicense\Check-VS-LicenseExpiration.ps1`
|
||||
- 起始于(可选):`C:\VSCELicense`(确保路径正确)
|
||||
|
||||
> ✅ **说明** :
|
||||
>
|
||||
> - `-ExecutionPolicy RemoteSigned`:允许本地脚本运行,避免执行策略限制。
|
||||
> - `"C:\VSCELicense\Check-VS-LicenseExpiration.ps1"`:替换为你实际的脚本路径。
|
||||
> - 如果脚本路径包含空格,请用双引号包裹。
|
||||
|
||||
### 🧩 步骤 5:设置条件(可选)
|
||||
|
||||
1. 切换到 **条件** 选项卡。
|
||||
2. 可以取消勾选“只有在计算机使用交流电源时才启动此任务”,确保任务在任何电源模式下都能运行。
|
||||
|
||||
### 🧩 步骤 6:设置设置(可选)
|
||||
|
||||
1. 切换到 **设置** 选项卡。
|
||||
2. 勾选“如果任务失败,按以下频率重新启动”并设置时间间隔(如每 1 分钟)。
|
||||
3. 勾选“如果任务运行时间超过以下时间,则停止任务”并设置合理时间(如 1 小时)。
|
||||
|
||||
### 🧩 步骤 7:保存任务
|
||||
|
||||
1. 点击 **确定** 。
|
||||
2. 如果弹出用户账户控制(UAC)提示,输入管理员凭据确认。
|
||||
|
||||
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 30 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 40 KiB |
@@ -37,3 +37,43 @@ pip uninstall package_name
|
||||
```
|
||||
|
||||
Pip会询问你是否确定卸载软件包,并删除相关的文件。
|
||||
|
||||
# Python __name__
|
||||
|
||||
首先需要了解 __name__ 是属于 python 中的内置类属性,就是它会天生就存在于一个 python 程序中,代表对应程序名称
|
||||
|
||||
```python
|
||||
import requests
|
||||
class requests(object):
|
||||
def __init__(self,url):
|
||||
self.url=url
|
||||
self.result=self.getHTMLText(self.url)
|
||||
def getHTMLText(url):
|
||||
try:
|
||||
r=requests.get(url,timeout=30)
|
||||
r.raise_for_status()
|
||||
r.encoding=r.apparent_encoding
|
||||
return r.text
|
||||
except:
|
||||
return "This is a error."
|
||||
print(__name__)
|
||||
```
|
||||
|
||||
结果:
|
||||
|
||||
```shell
|
||||
__main__
|
||||
Process finished with exit code 0
|
||||
```
|
||||
|
||||
当这个 pcRequests.py 作为模块被调用时,则它的 __name__ 就是它自己的名字:
|
||||
|
||||
```python
|
||||
import pcRequestspcRequestsc=pcRequestsc.__name__
|
||||
```
|
||||
|
||||
结果:
|
||||
|
||||
```shell
|
||||
'pcRequests'
|
||||
```
|
||||
|
||||
@@ -0,0 +1,606 @@
|
||||
---
|
||||
title: React
|
||||
date: 2025-07-23 15:56:46
|
||||
tags:
|
||||
---
|
||||
|
||||
# Vue 转 React 指南
|
||||
|
||||
## JSX
|
||||
|
||||
先介绍 React 唯一的一个语法糖:JSX。
|
||||
|
||||
理解 JSX 语法并不困难,简单记住一句话,遇到 `{}` 符号内部解析为 JS 代码,遇到成对的 `<>` 符号内部解析为 HTML 代码。
|
||||
|
||||
当你写下这个 React 组件时:
|
||||
|
||||
```jsx
|
||||
import React from 'react';
|
||||
|
||||
function MyComponent(props) {
|
||||
return <div>{props.hello}</div>
|
||||
}
|
||||
```
|
||||
|
||||
最终会被自动工具翻译成:
|
||||
|
||||
```jsx
|
||||
import React from 'react';
|
||||
|
||||
function MyComponent(props) {
|
||||
return React.createElement('div', null, props.hello);
|
||||
}
|
||||
```
|
||||
|
||||
React 就是通过这个小小语法糖,实现在 JS 里面写 HTML,可能有小伙伴会说 HTML 与 JS 分离不是更好吗?责职分明,混合只会更乱。但当你体验到代码自动提示,自动检查,以及调试时精确定位到一行代码的好处时,就清楚 React 和 Vue 的差距了。
|
||||
|
||||
## 文本插值
|
||||
|
||||
**vue种采用双括号**
|
||||
|
||||
```vue
|
||||
<span>Message: {{ msg }}</span>
|
||||
```
|
||||
|
||||
**react采用单括号**
|
||||
|
||||
```jsx
|
||||
function MyComponent(props) {
|
||||
let msg = 'XXX'
|
||||
return <div>{ msg }</div>
|
||||
}
|
||||
```
|
||||
|
||||
## Attribute 绑定
|
||||
|
||||
**vue中 想要响应式地绑定一个 attribute,应该使用 `v-bind` 指令**
|
||||
|
||||
```vue
|
||||
<div v-bind:id="dynamicId"></div>
|
||||
<div :id="dynamicId"></div>
|
||||
```
|
||||
|
||||
**react中,使用单引号,或者使用单括号包裹表示动态绑定**
|
||||
|
||||
```jsx
|
||||
function App () {
|
||||
let tmpID = '12'
|
||||
return (
|
||||
<div className='App'>
|
||||
<div id='12'>id</div>
|
||||
<div id={tmpID}>id</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
动态绑定多值:
|
||||
|
||||
```jsx
|
||||
function App () {
|
||||
let tmpObject = {
|
||||
id: 13,
|
||||
className: 'wrapper'
|
||||
}
|
||||
return (
|
||||
<div className='App'>
|
||||
<div {...tmpObject}>id</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
即:
|
||||
|
||||
<div id="13" class="wrapper">id</div>
|
||||
```
|
||||
|
||||
## 参数 Arguments
|
||||
|
||||
**某些指令会需要一个“参数”,Vue在指令名后通过一个冒号隔开做标识。例如用 `v-bind` 指令**
|
||||
|
||||
```vue
|
||||
<a v-bind:href="url"> ... </a>
|
||||
|
||||
<!-- 简写 -->
|
||||
<a :href="url"> ... </a>
|
||||
```
|
||||
|
||||
**React中则没有指令一说,而是采用如下方式:**
|
||||
|
||||
```jsx
|
||||
// href跳转
|
||||
function App () {
|
||||
let tmpURL = 'https://www.XXXXXXXX'
|
||||
return (
|
||||
<div className='App'>
|
||||
<a href={tmpURL}></a>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
## 使用 JS 表达式
|
||||
|
||||
**React 遇到 `{}` 符号内部解析为 JS 代码**
|
||||
|
||||
```jsx
|
||||
function App () {
|
||||
let tmpString = '--';
|
||||
return (
|
||||
<div className='App'>
|
||||
<div >{1 + 1}</div>
|
||||
<div >{'a' + 'b'}</div>
|
||||
<div >{`1${tmpString}1`}</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
即:
|
||||
|
||||
```html
|
||||
<div>2</div>
|
||||
<div>ab</div>
|
||||
<div>1--1</div>
|
||||
```
|
||||
|
||||
## 事件处理
|
||||
|
||||
**Vue中绑定事件处理:**
|
||||
|
||||
```vue
|
||||
<!-- `greet` 是上面定义过的方法名 -->
|
||||
<button @click="greet">Greet</button>
|
||||
```
|
||||
|
||||
**React可以通过在组件中声明 事件处理 函数来响应事件**
|
||||
|
||||
React中点击事件使用小驼峰形式:onClick
|
||||
|
||||
在标签上写函数:
|
||||
|
||||
```jsx
|
||||
function App () {
|
||||
return (
|
||||
<div className='App'>
|
||||
<div onClick={() => alert('点击出现弹框')}>按钮</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
提前声明函数:
|
||||
|
||||
```jsx
|
||||
function App () {
|
||||
function myFun () {
|
||||
alert('点击出现弹框')
|
||||
}
|
||||
return (
|
||||
<div className='App'>
|
||||
<div onClick={myFun}>按钮</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
注意,`onClick={handleClick}` 的结尾没有小括号!不要 **调用** 事件处理函数:你只需 **传递给事件** 即可。当用户点击按钮时,React 会调用你的事件处理函数。
|
||||
|
||||
函数传参:
|
||||
|
||||
```jsx
|
||||
function App () {
|
||||
function myFun (str) {
|
||||
alert(str)
|
||||
}
|
||||
return (
|
||||
<div className='App'>
|
||||
<div onClick={() => myFun('点击出现弹框')}>按钮</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
## 动态参数
|
||||
|
||||
**Vue在指令参数上也可以使用一个 JavaScript 表达式,需要包含在一对方括号内:**
|
||||
|
||||
```vue
|
||||
<a v-bind:[attributeName]="url"> ... </a>
|
||||
|
||||
<!-- 简写 -->
|
||||
<a :[attributeName]="url"> ... </a>
|
||||
```
|
||||
|
||||
举例来说,如果你的组件实例有一个数据属性 `attributeName`,其值为 `"href"`,那么这个绑定就等价于 `v-bind:href`。
|
||||
|
||||
**React 也可以通过动态参数绑定**
|
||||
|
||||
```jsx
|
||||
function App () {
|
||||
const obj = {
|
||||
onClick: () => alert('点击出现弹框'),
|
||||
// ...还可以写更多事件
|
||||
}
|
||||
return (
|
||||
<div className='App'>
|
||||
<div {...obj}>按钮</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
## 修饰符 Modifiers
|
||||
|
||||
vue 修饰符是以点开头的特殊后缀
|
||||
|
||||
表明指令需要以一些特殊的方式被绑定。例如 `.prevent` 修饰符会告知 `v-on` 指令对触发的事件调用 `event.preventDefault()`:
|
||||
|
||||
```vue
|
||||
<form @submit.prevent="onSubmit">...</form>
|
||||
```
|
||||
|
||||
React 则是依靠于JS基础
|
||||
|
||||
```jsx
|
||||
function App () {
|
||||
function onSubmit(e){
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
}
|
||||
return (
|
||||
<div className='App'>
|
||||
<form onSubmit={onSubmit}>
|
||||
<button type='submit'></button>
|
||||
</form>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
## 响应式
|
||||
|
||||
**为了实现视图更新,VUE中响应式是一个重要的概念**
|
||||
|
||||
**而 React 中并没有响应式这个概念,要实现视图更新,需要在 React 引入 `useState`**
|
||||
|
||||
通常,你会希望你的组件 “记住” 一些信息并展示出来。例如,也许你想计算一个按钮被点击的次数。要做到这一点,你需要在你的组件中添加 **state**。
|
||||
|
||||
首先,从 React 引入 `useState`:
|
||||
|
||||
```jsx
|
||||
import { useState } from 'react';
|
||||
```
|
||||
|
||||
现在你可以在你的组件中声明一个 **state 变量**:
|
||||
|
||||
```jsx
|
||||
function MyButton() {
|
||||
const [count, setCount] = useState(0);
|
||||
// ...
|
||||
```
|
||||
|
||||
你将从 `useState` 中获得两样东西:当前的 state(`count`),以及用于更新它的函数(`setCount`)。你可以给它们起任何名字,但按照惯例,需要像这样 `[something, setSomething]` 为它们命名。
|
||||
|
||||
第一次显示按钮时,`count` 的值为 `0`,因为你把 `0` 传给了 `useState()`。当你想改变 state 时,调用 `setCount()` 并将新的值传递给它。点击该按钮计数器将递增:
|
||||
|
||||
```jsx
|
||||
function MyButton() {
|
||||
const [count, setCount] = useState(0);
|
||||
function handleClick() {
|
||||
setCount(count + 1);
|
||||
}
|
||||
|
||||
return (
|
||||
<button onClick={handleClick}>
|
||||
Clicked {count} times
|
||||
</button>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
React 将再次调用你的组件函数。这次,`count` 会变成 `1`。接着,变成 `2`。以此类推。
|
||||
|
||||
如果你多次渲染同一个组件,每个组件都会拥有自己的 state。你可以尝试点击不同的按钮:
|
||||
|
||||
## 计算属性
|
||||
|
||||
Vue中使用 computed 来实现计算属性(缓存计算的结果)
|
||||
|
||||
**React 在组件的顶层调用 `useMemo` 来缓存每次重新渲染都需要计算的结果**
|
||||
|
||||
```jsx
|
||||
import { useState } from 'react';
|
||||
import { useMemo } from 'react';
|
||||
|
||||
function App () {
|
||||
const [user] = useState({ firstname: 'a', lastname: 'b' })
|
||||
|
||||
const fullname = useMemo(() => {
|
||||
return user.firstname + user.lastname;
|
||||
}, [user.firstname, user.lastname])
|
||||
|
||||
return (
|
||||
<div className='App'>
|
||||
{fullname}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
**useMemo(calculateValue, dependencies)**
|
||||
|
||||
参数
|
||||
|
||||
- `calculateValue`:要缓存计算值的函数。它应该是一个没有任何参数的纯函数,并且可以返回任意类型。React 将会在首次渲染时调用该函数;在之后的渲染中,如果 `dependencies` 没有发生变化,React 将直接返回相同值。否则,将会再次调用 `calculateValue` 并返回最新结果,然后缓存该结果以便下次重复使用。
|
||||
- `dependencies`:所有在 `calculateValue` 函数中使用的响应式变量组成的数组。响应式变量包括 props、state 和所有你直接在组件中定义的变量和函数。如果你在代码检查工具中 [配置了 React](https://react.docschina.org/learn/editor-setup#linting),它将会确保每一个响应式数据都被正确地定义为依赖项。依赖项数组的长度必须是固定的并且必须写成 `[dep1, dep2, dep3]` 这种形式。React 使用 [`Object.is`](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/is) 将每个依赖项与其之前的值进行比较。
|
||||
|
||||
## 绑定 HTML class
|
||||
|
||||
数据绑定的一个常见需求场景是操纵元素的 CSS class 列表和内联样式。因为 `class` 和 `style` 都是 attribute
|
||||
|
||||
Vue中可以给 `:class` (`v-bind:class` 的缩写) 传递一个对象来动态切换 class:
|
||||
|
||||
```vue
|
||||
<div :class="{ active: isActive }"></div>
|
||||
```
|
||||
|
||||
上面的语法表示 `active` 是否存在取决于数据属性 `isActive` 的真假值。
|
||||
|
||||
React实现方式基于js语法,其实有多种实现方式,列举三元运算符方式如下:
|
||||
|
||||
```jsx
|
||||
function App () {
|
||||
let showColor = false
|
||||
return (
|
||||
// 现有box-show、box-hide两个class样式
|
||||
<div className={showColor ? 'box-show' : 'box-hide'}></div>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
## 语法糖转换
|
||||
|
||||
习惯 Vue 的同学都知道很多语法糖,比如 `v-if`、`v-for`、`v-bind`、`v-on` 等,相比 Vue,React 只有一个语法糖,那就是 jsx/tsx。`v-if` 这些功能在 React 上都是通过原生 javascript 实现的,慢慢你会发现,其实你学的不是 React,而是 Javascipt,React 赋予你通过 js 完整控制组件的能力,这部分明显比 Vue 的语法糖更加灵活,糖太多容易引来虫子(Bug)
|
||||
|
||||
条件渲染
|
||||
|
||||
vue 中写法是这样:
|
||||
|
||||
```vue
|
||||
<div>
|
||||
<h1 v-if="ishow">Vue is awesome!</h1>
|
||||
<h1 v-else>else</h1>
|
||||
</div>
|
||||
```
|
||||
|
||||
在 React 函数组件中,只需使用 js 三目运算符语法即可完成条件渲染的功能。或者使用 && 逻辑,记住下面一句话就能过理解了:
|
||||
|
||||
> 遇到 `{}` 符号内部解析为 JS 代码,遇到成对的 `<>` 符号内部解析为 HTML 代码
|
||||
|
||||
```jsx
|
||||
function App () {
|
||||
const ishow = false
|
||||
return (
|
||||
<div>
|
||||
{ishow ? <div>awesome</div> : <div>else</div>}
|
||||
{ishow && <h1>React!</h1>}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
## 列表渲染
|
||||
|
||||
Vue中通过v-for进行列表渲染
|
||||
|
||||
**React 通过 js 的数组语法 map,将数据对象映射为 DOM 对象**。只需学会 js,无需记住各种指令,如果要做列表过滤,直接使用 `items.filter(...).map(...)` 链式调用即可,语法上更加灵活,如果为了提高渲染性能,使用 useMemo 进行优化即可,类似 Vue 的 computed。
|
||||
|
||||
```jsx
|
||||
function App () {
|
||||
const arr = [{ message: 'react' }, { message: 'JS' }]
|
||||
return (
|
||||
<div>
|
||||
{arr.map((items, index) => <li key={index}>{items.message}</li>)}
|
||||
</div >
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
## 侦听器
|
||||
|
||||
Vue中使用 watch监听数据变化,触发回调
|
||||
|
||||
React中可以使用 useEffect 实现
|
||||
|
||||
```jsx
|
||||
function App () {
|
||||
const [user, setUser] = useState({
|
||||
firstname: 'a',
|
||||
lastname: 'b'
|
||||
})
|
||||
useEffect(() => {
|
||||
console.log("1111")
|
||||
}, [user.firstname])
|
||||
return (
|
||||
<div>
|
||||
<button onClick={() => setUser({ ...user, firstname: 'a2' })}></button>
|
||||
</div >
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
# 父子组件传递事件
|
||||
|
||||
## 子组件是模态框,确定按钮需要增加loading状态
|
||||
|
||||
### **子组件:增加 `confirmLoading` 状态并优化 `handleOk` 方法**
|
||||
|
||||
```tsx
|
||||
import React, { useState } from 'react';
|
||||
import { Modal, Checkbox, Input, message } from 'antd';
|
||||
import { useTranslation } from 'react-i18next'
|
||||
|
||||
const { TextArea } = Input;
|
||||
|
||||
interface FeedbackModalProps {
|
||||
open: boolean;
|
||||
onOk: (selectedOption: number | null, feedbackText: string) => Promise<void>;
|
||||
onCancel: () => void;
|
||||
}
|
||||
|
||||
const FeedbackModal: React.FC<FeedbackModalProps> = ({ open, onOk, onCancel }) => {
|
||||
const [selectedOption, setSelectedOption] = useState<number | null>(null);
|
||||
const [feedbackText, setFeedbackText] = useState<string>('');
|
||||
const { t } = useTranslation()
|
||||
const [confirmLoading, setConfirmLoading] = useState(false);
|
||||
|
||||
const handleOk = async () => {
|
||||
if (!feedbackText) {
|
||||
message.warning('请填写反馈建议');
|
||||
return;
|
||||
}
|
||||
setConfirmLoading(true)
|
||||
try {
|
||||
await onOk(selectedOption, feedbackText);
|
||||
} finally {
|
||||
setConfirmLoading(false)
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
return (
|
||||
<Modal
|
||||
title="反馈"
|
||||
open={open}
|
||||
onOk={handleOk}
|
||||
onCancel={onCancel}
|
||||
okText={`${t('common.operation.confirm')}`}
|
||||
cancelText={`${t('common.operation.cancel')}`}
|
||||
confirmLoading={confirmLoading}
|
||||
>
|
||||
{/* <div>
|
||||
<Checkbox
|
||||
checked={selectedOption === 0}
|
||||
onChange={() => setSelectedOption(0)}
|
||||
>
|
||||
新增
|
||||
</Checkbox>
|
||||
<Checkbox
|
||||
checked={selectedOption === 1}
|
||||
onChange={() => setSelectedOption(1)}
|
||||
>
|
||||
修改
|
||||
</Checkbox>
|
||||
</div> */}
|
||||
<TextArea
|
||||
rows={4}
|
||||
placeholder="请输入您的反馈建议"
|
||||
value={feedbackText}
|
||||
onChange={(e) => setFeedbackText(e.target.value)}
|
||||
/>
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
|
||||
export default FeedbackModal;
|
||||
|
||||
```
|
||||
|
||||
### **父组件:确保 `handleFeedbackSubmit` 返回 Promise**
|
||||
|
||||
```tsx
|
||||
const handleFeedbackSubmit = useCallback(
|
||||
async (selectedOption: number | null, feedbackText: string) => {
|
||||
console.log(currentMessageId);
|
||||
console.log(currentFeedback);
|
||||
|
||||
try {
|
||||
// 构造请求参数
|
||||
const requestBody = {
|
||||
operationType: currentFeedback!.rating, // 0 或 1
|
||||
feedbackText, // 用户反馈建议
|
||||
conversationId: currentConversationId, // 会话 ID
|
||||
messageId: currentMessageId, // 消息 ID
|
||||
username: getCookieValue('username'), // 用户名
|
||||
};
|
||||
|
||||
// 调用 Java 接口
|
||||
const javaResponse = await fetch(
|
||||
`/dev-api/api/conversation/feedback`,
|
||||
{
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify(requestBody),
|
||||
}
|
||||
);
|
||||
|
||||
// 调用原有的 updateFeedback 函数
|
||||
await updateFeedback(
|
||||
{
|
||||
url: `/messages/${currentMessageId}/feedbacks`,
|
||||
body: { rating: currentFeedback!.rating },
|
||||
},
|
||||
// isInstalledApp,
|
||||
// appId
|
||||
);
|
||||
|
||||
// 显示成功通知
|
||||
notify({ type: "success", message: t("common.api.success") });
|
||||
|
||||
if (resolveFeedback) {
|
||||
resolveFeedback(true); // 用户取消了反馈
|
||||
setResolveFeedback(null);
|
||||
}
|
||||
|
||||
// 关闭对话框
|
||||
setIsFeedbackModalVisible(false);
|
||||
} catch (error) {
|
||||
console.error("Error:", error);
|
||||
notify({ type: "error", message: t("common.api.failed") });
|
||||
} finally {
|
||||
setIsSubmittingNow(false);
|
||||
}
|
||||
},
|
||||
[
|
||||
currentMessageId,
|
||||
currentFeedback,
|
||||
currentConversationId,
|
||||
isInstalledApp,
|
||||
appId,
|
||||
notify,
|
||||
t,
|
||||
]
|
||||
);
|
||||
```
|
||||
|
||||
父组件调用子组件部分
|
||||
|
||||
```tsx
|
||||
<FeedbackModal
|
||||
open={isFeedbackModalVisible}
|
||||
onOk={handleFeedbackSubmit}
|
||||
onCancel={() => {
|
||||
if (resolveFeedback) {
|
||||
resolveFeedback(false); // 用户取消了反馈
|
||||
setResolveFeedback(null);
|
||||
}
|
||||
setIsFeedbackModalVisible(false)
|
||||
}}
|
||||
/>
|
||||
```
|
||||
|
||||
### **关键点说明**
|
||||
|
||||
1. **子组件内部管理加载状态**
|
||||
通过 `useState` 创建 `isLoading` 状态,并在 `handleOk` 中控制其值。点击按钮时,`isLoading` 变为 `true`,请求结束后变为 `false`。
|
||||
2. **`okButtonProps` 绑定加载状态**
|
||||
Ant Design 的 `Modal` 组件支持通过 `okButtonProps` 自定义按钮属性,这里将 `loading` 绑定到 `isLoading` 状态。
|
||||
3. **`onOk` 作为异步函数传递**
|
||||
父组件的 `handleFeedbackSubmit` 是 `async` 函数,返回 Promise。子组件通过 `await onOk()` 确保加载状态在请求结束后更新。
|
||||
4. **错误处理不影响加载状态**
|
||||
使用 `try...finally` 确保无论请求成功或失败,`isLoading` 都会被重置。
|
||||
@@ -46,7 +46,7 @@ top_img: https://gcore.jsdelivr.net/gh/volantis-x/cdn-wallpaper/abstract/B951AE1
|
||||
|
||||
## 设置引用图片存储路径
|
||||
|
||||

|
||||

|
||||
|
||||
## Typora添加右键新建Markdown文件
|
||||
|
||||
@@ -98,7 +98,7 @@ Windows Registry Editor Version 5.00
|
||||
|
||||
删除多余的文件(尤其是有一个什么Markdown File),只保留如下的两项。然后关闭注册表,即可修复bug
|
||||
|
||||

|
||||

|
||||
|
||||
|
||||
|
||||
@@ -125,9 +125,9 @@ Windows Registry Editor Version 5.00
|
||||
```
|
||||
|
||||
|
||||

|
||||

|
||||
|
||||

|
||||

|
||||
|
||||
## 上传图片至Minio
|
||||
|
||||
@@ -191,4 +191,18 @@ picgo upload /path/to/your/image.png
|
||||
|
||||
### Typora设置
|
||||
|
||||

|
||||

|
||||
|
||||
## 主题
|
||||
|
||||
### typora-gitbook-theme
|
||||
|
||||
https://github.com/h16nning/typora-gitbook-theme
|
||||
|
||||
### typora-ladder-theme
|
||||
|
||||
https://github.com/guangzhengli/typora-ladder-theme
|
||||
|
||||
### Mdmdt
|
||||
|
||||
[cayxc/Mdmdt: Typora极简文档主题Mdmdt,包含亮色和暗色两种主题,是深度定制的个性化Typora主题;Typora minimalist document theme Mdmdt. Featuring both light and dark themes, it is a deeply customized personalized Typora theme.](https://github.com/cayxc/Mdmdt)
|
||||
|
||||
|
After Width: | Height: | Size: 42 KiB |
|
After Width: | Height: | Size: 69 KiB |
|
After Width: | Height: | Size: 147 KiB |
|
After Width: | Height: | Size: 63 KiB |
|
After Width: | Height: | Size: 3.3 KiB |
@@ -69,10 +69,12 @@ vim 的各种工作模式可以通过不同的键进行切换,用户统一使
|
||||
|
||||
在底线命令模式中,基本的命令有(已经省略了冒号):
|
||||
|
||||
- :w: 保存文件
|
||||
- :q: 退出 Vim 编辑器
|
||||
- :wq: 保存文件并退出 Vim 编辑器
|
||||
- :q!: 强制退出 Vim 编辑器,不保存修改
|
||||
- :w 保存文件
|
||||
- :q 退出 Vim 编辑器
|
||||
- :wq 保存文件并退出 Vim 编辑器
|
||||
- :q! 强制退出 Vim 编辑器,不保存修改
|
||||
- :set nu 开启行号
|
||||
- :set nonu 关闭行号
|
||||
|
||||
按`ESC`键可随时退出底线命令模式。
|
||||
|
||||
@@ -183,4 +185,20 @@ vim 的各种工作模式可以通过不同的键进行切换,用户统一使
|
||||
</thead>
|
||||
</table>
|
||||
</center>
|
||||
# Vim配置文件
|
||||
|
||||
## 当前用户配置文件(~/.vimrc)
|
||||
|
||||
若在当前用户目录下没有`.vimrc`,则手动新建即可
|
||||
|
||||
```bash
|
||||
vim ~/.vimrc
|
||||
```
|
||||
|
||||
其中可添加如命令模式中的命令,比如`set nu`,之后再打开vim则默认开启行号
|
||||
|
||||
```
|
||||
set nu
|
||||
```
|
||||
|
||||
`:wq`保存退出后,需使用`source ~/.vimrc`使改动生效
|
||||
|
||||
@@ -16,6 +16,32 @@ tags:
|
||||
|
||||
### 配置远程连接Linux密码免登录
|
||||
|
||||
首先使用 `PuTTY Key Generator`生成ppk
|
||||
|
||||

|
||||
|
||||
出现进度条,在框内摇晃鼠标,直到进度条满,就可以看到生成的公钥了,私钥是需要保存到本地的,最好保存到`~/.ssh`目录下
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
框内是生成的公钥,可以保存到本地,也可以直接复制到要连接的Linux服务器上的`~/.ssh/authorized_keys`文件内
|
||||
|
||||

|
||||
|
||||
因为刚刚保存的私钥是`ppk`格式的,如果是SSH连接用,需要转换一下,`PuTTY Key Generator`同样有这个功能
|
||||
|
||||
如果是刚生成好的,可以直接点击上方工具栏 Conversions -> Export OpenSSH Key 然后保存到`~/.ssh`目录下。
|
||||
|
||||

|
||||
|
||||
如果是要打开以前生成的密钥,File -> Load private Key。然后再重复上述 Conversions -> Export OpenSSH Key 步骤即可。
|
||||
|
||||

|
||||
|
||||
编辑配置文件,一般位于`~/.ssh/config`
|
||||
|
||||
```shell
|
||||
@@ -36,7 +62,7 @@ vim ~/.ssh/authorized_keys
|
||||
|
||||
将秘钥对应的公钥复制上去
|
||||
|
||||

|
||||

|
||||
|
||||
保存即可
|
||||
|
||||
@@ -50,39 +76,41 @@ vim /etc/ssh/sshd_config
|
||||
PubkeyAuthentication yes
|
||||
|
||||
# :wq 保存
|
||||
# 重启sshd服务
|
||||
# 重启sshd服务 AlmaLinux 下
|
||||
systemctl restart sshd
|
||||
# ubuntu 下
|
||||
sudo systemctl restart ssh
|
||||
```
|
||||
|
||||
Windows `~/.ssh` 目录属性中 安全 -> 高级
|
||||
|
||||

|
||||

|
||||
|
||||
需 停用继承,我这里已经停用
|
||||
|
||||

|
||||

|
||||
|
||||
然后点击 添加,选择主体
|
||||
|
||||

|
||||

|
||||
|
||||
选择高级
|
||||
|
||||

|
||||

|
||||
|
||||
点击 立即查找
|
||||
|
||||

|
||||

|
||||
|
||||
选择 Administrator 和 SYSTEM
|
||||
|
||||

|
||||

|
||||
|
||||

|
||||

|
||||
|
||||
点击两次 确定后,将 基本权限改为 完全控制
|
||||
|
||||

|
||||

|
||||
|
||||
再次点击确定
|
||||
|
||||
|
||||
|
After Width: | Height: | Size: 61 KiB |
|
After Width: | Height: | Size: 31 KiB |
|
After Width: | Height: | Size: 38 KiB |
|
After Width: | Height: | Size: 31 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 41 KiB |
|
After Width: | Height: | Size: 43 KiB |
|
After Width: | Height: | Size: 43 KiB |
|
After Width: | Height: | Size: 31 KiB |
@@ -1832,6 +1832,10 @@ yarn build
|
||||
yarn remove pte-ui
|
||||
# 安装依赖
|
||||
yarn add pte-ui@2.1.54
|
||||
# 查看缓存路径
|
||||
yarn cache dir
|
||||
# 修改缓存路径
|
||||
yarn config set cache-folder "E:\\Yarn\\Cache"
|
||||
|
||||
|
||||
```
|
||||
@@ -1861,6 +1865,25 @@ yarn
|
||||
| npm install [package]@[version] | yarn add [package]@[version] | 安装指定版本的包 |
|
||||
| npm rebuild | yarn install --force | 重新下载所有包 |
|
||||
|
||||
##
|
||||
|
||||
## pnpm包管理器
|
||||
|
||||
```shell
|
||||
# 查看缓存存储位置
|
||||
pnpm store path
|
||||
# 设置缓存存储位置
|
||||
pnpm config set store-dir <new path>
|
||||
# 修改全局源
|
||||
pnpm config set registry https://registry.npmmirror.com
|
||||
# 修改项目源
|
||||
pnpm config set registry https://registry.npmmirror.com --save
|
||||
# 查看当前设置的源
|
||||
pnpm config get registry
|
||||
```
|
||||
|
||||
|
||||
|
||||
## 快速删除 node_modules
|
||||
|
||||
利用 npm 包 rimraf 快速删除 `node_modules` 文件夹
|
||||
@@ -1879,6 +1902,51 @@ rimraf node_modules
|
||||
|
||||
|
||||
|
||||
# NVM
|
||||
|
||||
> nvm(Node Version Manager)是一个非常有用的工具,可以让您在同一台机器上安装和管理多个 Node.js 版本。
|
||||
>
|
||||
> [nvm-sh/nvm: Node Version Manager - POSIX-compliant bash script to manage multiple active node.js versions (github.com)](https://github.com/nvm-sh/nvm?tab=readme-ov-file#installing-and-updating)
|
||||
|
||||
**nvm 常用命令:**
|
||||
|
||||
```shell
|
||||
# 查看 nvm 版本
|
||||
nvm --version
|
||||
|
||||
# 列出所有可安装的 Node.js 版本
|
||||
nvm list-remote
|
||||
# Windows 上使用
|
||||
nvm list available
|
||||
|
||||
# 安装最新的 LTS 版本
|
||||
nvm install --lts
|
||||
|
||||
# 安装特定版本
|
||||
nvm install 18.17.0
|
||||
nvm install 16.20.1
|
||||
|
||||
# 列出已安装的版本
|
||||
nvm list
|
||||
# 或
|
||||
nvm ls
|
||||
|
||||
# 切换到特定版本
|
||||
nvm use 18.17.0
|
||||
|
||||
# 设置默认版本
|
||||
nvm alias default 18.17.0
|
||||
|
||||
# 查看当前使用的版本
|
||||
nvm current
|
||||
|
||||
# 卸载特定版本
|
||||
nvm uninstall 16.20.1
|
||||
|
||||
# 查看当前使用的npm的目录
|
||||
npm prefix -g
|
||||
```
|
||||
|
||||
# npx
|
||||
|
||||
npm大家都知道,是node的包管理器,npx虽然也见过,但似乎较少用过,那npx到底是什么呢?
|
||||
|
||||
@@ -0,0 +1,135 @@
|
||||
---
|
||||
title: Windows Server
|
||||
date: 2025-07-21 10:53:55
|
||||
tags:
|
||||
---
|
||||
|
||||
# Web Deploy 部署任务失败解决方案
|
||||
|
||||
## 报错信息:
|
||||
|
||||
```shell
|
||||
C:\Program Files\dotnet\sdk\9.0.302\Sdks\Microsoft.NET.Sdk.Publish\targets\PublishTargets\Microsoft.NET.Sdk.Publish.MSDeploy.targets(140,5): 错误 : Web 部署任务失败。
|
||||
((2025/7/21 10:43:25)在远程计算机上处理请求时出错。)
|
||||
(2025/7/21 10:43:25)在远程计算机上处理请求时出错。
|
||||
无法执行此操作。请与服务器管理员联系,检查授权和委派设置。
|
||||
```
|
||||
|
||||
## 解决方法:
|
||||
|
||||
计算机管理
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
之后打开服务,找到Web 部署代理服务,重新启动一下
|
||||
|
||||

|
||||
|
||||
# IIS(Internet Information Services)
|
||||
|
||||
## 优化回收策略
|
||||
|
||||

|
||||
|
||||
- 回收 > 固定时间间隔(分钟)
|
||||
|
||||
一个时间段,超过该时间段,应用程序池将回收。值为 0 ,则应用程序池不会按固定间隔回收
|
||||
|
||||
默认值:1740分钟,29小时
|
||||
|
||||
优化设置:改为0 。因为无法避免在高峰期发生回收。同时设置“回收 > 特定时间”
|
||||
|
||||
- 回收 > 特定时间
|
||||
|
||||
应用程序池进行回收的一组特定的本地时间(24小时制)
|
||||
|
||||
优化设置:固定在低峰期时回收。eg:设定为 04:00 、15:30 等
|
||||
|
||||
另外,也可以使用windows计划任务实现iis站点每周六晚定时回收
|
||||
|
||||
- 进程模型 > 闲置超时(分钟)
|
||||
|
||||
一个时间段,设定工作进程允许保持闲置状态的最大时间间隔,超过该时间就会自动关闭。
|
||||
|
||||
优化设置:改为0,避免内存信息频繁被回收清空。同时设置“回收 > 特定时间”
|
||||
|
||||
- 进程模型 > 空闲超时操作
|
||||
|
||||
默认是“Terminate”(另一个选项是“Suspend”)。
|
||||
|
||||
Terminate 表示一旦超时就终止服务,并回收工作进程的缓冲区的内存;
|
||||
|
||||
Suspend 则悬停等待,暂不回收缓冲区内存。
|
||||
|
||||
# Windows 运行命令
|
||||
|
||||
## 进入Windows 设置
|
||||
|
||||
```cmd
|
||||
ms-settings:
|
||||
```
|
||||
|
||||
## 远程桌面连接
|
||||
|
||||
```cmd
|
||||
mstsc
|
||||
```
|
||||
|
||||
### 本地组策略编辑器
|
||||
|
||||
```cmd
|
||||
gpedit.msc
|
||||
```
|
||||
|
||||
## 服务
|
||||
|
||||
```cmd
|
||||
services.msc
|
||||
```
|
||||
|
||||
## 设备管理器
|
||||
|
||||
```cmd
|
||||
devmgmt.msc
|
||||
```
|
||||
|
||||
## 控制面板
|
||||
|
||||
```cmd
|
||||
control
|
||||
```
|
||||
|
||||
## 注册表编辑器
|
||||
|
||||
```cmd
|
||||
regedit
|
||||
```
|
||||
|
||||
# PowerShell
|
||||
|
||||
## 激活工具命令
|
||||
|
||||
```powershell
|
||||
irm https://massgrave.dev/get | iex
|
||||
```
|
||||
|
||||
# CMD
|
||||
|
||||
## 7zip
|
||||
|
||||
### 解压压缩包内的部分文件或目录到指定目录下
|
||||
|
||||
```cmd
|
||||
"C:\Users\yun\AppData\Local\Microsoft\WindowsApps\7z.exe" x "D:\source\source.7z" -o"D:" "source\repos\ruoyi-ai\*"
|
||||
```
|
||||
|
||||
**详细解释:**
|
||||
|
||||
- `"C:\Users\yun\AppData\Local\Microsoft\WindowsApps\7z.exe"`: 这是 7-Zip 可执行文件的完整路径。
|
||||
- `x`: 解压命令,会保留压缩包内的目录结构。
|
||||
- `"D:\source\source.7z"`: 要解压的源压缩包的完整路径。
|
||||
- `-o"D:"`: 这是指定**目标解压目录**。所有从压缩包中解压出来的内容都会放到这个目录下。
|
||||
- **注意:** `-o` 后面直接跟目标文件夹的完整路径,不带 `*`。
|
||||
- `"source\repos\ruoyi-ai\*"`: 这是**压缩包内部想要解压的目录名称**。请确保这个名称与压缩包内的实际目录名完全一致(大小写敏感)。
|
||||
|
After Width: | Height: | Size: 145 KiB |
|
After Width: | Height: | Size: 141 KiB |
|
After Width: | Height: | Size: 127 KiB |
@@ -0,0 +1,318 @@
|
||||
---
|
||||
title: macOS
|
||||
date: 2025-09-26 22:54:01
|
||||
tags:
|
||||
---
|
||||
|
||||
# 环境配置
|
||||
|
||||
## Homebrew
|
||||
|
||||
> 官网:https://brew.sh/
|
||||
|
||||
### 介绍
|
||||
|
||||
Homebrew 就像 Mac 的智能软件管家。
|
||||
|
||||
- 你可以用它安装需要的软件(比如 Python、MySQL),它会自动下载、安装、配置,甚至帮你处理依赖(比如装 A 需要先装 B)。
|
||||
- 卸载时,它会把软件和相关文件清理干净,不留垃圾。
|
||||
- 支持下载命令行工具(如`git`)和图形应用(如`chrome`)
|
||||
|
||||
### 安装
|
||||
|
||||
安装前需开启魔法,防止拉取失败。
|
||||
|
||||
```shell
|
||||
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
|
||||
```
|
||||
|
||||
### 常见命令
|
||||
|
||||
| 操作类型 | 命令 | 功能说明 |
|
||||
| -------- | ----------------------------- | ------------------------------ |
|
||||
| 安装 | brew install [package name] | 安装软件(自动处理依赖) |
|
||||
| 卸载 | brew uninstall [package name] | 彻底卸载软件(并自动清理依赖) |
|
||||
| 更新 | brew update | 更新 Homebrew 本体 |
|
||||
| | brew update [package name] | 更新指定软件 |
|
||||
| | brew upgrade | 更新所有已安装软件 |
|
||||
| 查询 | brew info [package name] | 查看指定软件详细信息 |
|
||||
| | brew list | 列出所有已安装软件 |
|
||||
| 清理 | brew cleanup -n | 预览可清理的旧版本 |
|
||||
| | brew cleanup [package name] | 清理指定软件的旧版本 |
|
||||
|
||||
### 高阶技巧
|
||||
|
||||
#### 服务管理系统(类似 Linux 的 systemd)
|
||||
|
||||
```shell
|
||||
brew services start mysql # 启动 MySQL 服务
|
||||
brew services stop redis # 停止 Redis 服务
|
||||
brew services list # 查看所有服务状态
|
||||
```
|
||||
|
||||
#### 精准版本控制
|
||||
|
||||
```shell
|
||||
brew install python@3.9 # 安装指定 Python 版本为 3.9
|
||||
brew pin python@3.9 # 锁定版本防止误升级
|
||||
brew unpin python@3.9 # 解除锁定
|
||||
```
|
||||
|
||||
### 卸载
|
||||
|
||||
```shell
|
||||
# 卸载脚本(谨慎执行!)
|
||||
/bin/bash -c "$(curl -fsSL <https://raw.githubusercontent.com/Homebrew/install/master/uninstall.sh>)"
|
||||
```
|
||||
|
||||
### 目录结构解析
|
||||
|
||||
`Homebrew`在下载软件后,会将数据放在以下目录中
|
||||
|
||||
| **路径** | **作用** |
|
||||
| ---------------------- | ---------------------------- |
|
||||
| `/opt/homebrew` | ARM 芯片主目录(M1/M2 专用) |
|
||||
| `/usr/local` | Intel 芯片主目录 |
|
||||
| `/opt/homebrew/Cellar` | 所有安装的软件本体 |
|
||||
|
||||
## oh my zsh
|
||||
|
||||
通过下载脚本安装命令
|
||||
|
||||
```shell
|
||||
sh -c "$(curl -fsSL https://gitee.com/pocmon/ohmyzsh/raw/master/tools/install.sh)"
|
||||
```
|
||||
|
||||
剩余安装过程跟 `Linux`中的保持一致。
|
||||
|
||||
## nvm
|
||||
|
||||
### 通过 Homebrew 安装
|
||||
|
||||
```shell
|
||||
brew install nvm
|
||||
```
|
||||
|
||||
这种方式需要手动配置环境变量。
|
||||
|
||||
`zsh`下编辑 `~/.zshrc`环境变量配置文件,文件末尾添加以下内容。
|
||||
|
||||
```ini
|
||||
export NVM_DIR="$HOME/.nvm"
|
||||
[ -s "/opt/homebrew/opt/nvm/nvm.sh" ] && \. "/opt/homebrew/opt/nvm/nvm.sh"
|
||||
[ -s "/opt/homebrew/opt/nvm/etc/bash_completion.d/nvm" ] && \. "/opt/homebrew/opt/nvm/etc/bash_completion.d/nvm"
|
||||
```
|
||||
|
||||
`:wq`保存,然后`source ~/.zshrc`即可应用。
|
||||
|
||||
### 安装最新版本 node
|
||||
|
||||
```shell
|
||||
nvm install node
|
||||
```
|
||||
|
||||
安装后会自动`use`。
|
||||
|
||||
## colima
|
||||
|
||||
### 介绍
|
||||
|
||||
colima 是 macOS 上的容器运行时。
|
||||
|
||||
### 安装
|
||||
|
||||
```shell
|
||||
# Homebrew
|
||||
brew install colima
|
||||
```
|
||||
|
||||
启动服务
|
||||
|
||||
```shell
|
||||
brew services start colima
|
||||
```
|
||||
|
||||
启动 colima
|
||||
|
||||
```shell
|
||||
colima start
|
||||
```
|
||||
|
||||
### 运行时
|
||||
|
||||
初始启动时,Colima会使用默认为Docker的用户指定的运行时启动。
|
||||
|
||||
#### Docker
|
||||
|
||||
Docker运行时需要Docker客户端。可以使用`Homebrew`安装。
|
||||
|
||||
```shell
|
||||
brew install docker
|
||||
```
|
||||
|
||||
Colima启动之后,您可以使用MacOS上的Docker客户端,没有其他设置。
|
||||
|
||||
若需使用容器编排,就还需要安装`Docker Compose`
|
||||
|
||||
```shell
|
||||
brew install docker-compose
|
||||
```
|
||||
|
||||
创建符号链接
|
||||
|
||||
使 Docker 能够找到 Docker Compose
|
||||
|
||||
```shell
|
||||
mkdir -p ~/.docker/cli-plugins
|
||||
ln -sfn /opt/homebrew/opt/docker-compose/bin/docker-compose ~/.docker/cli-plugins/docker-compose
|
||||
```
|
||||
|
||||
启动`COlima`并指定使用`Docker`运行时。
|
||||
|
||||
```shell
|
||||
colima start --runtime docker
|
||||
```
|
||||
|
||||
### 配置
|
||||
|
||||
#### 镜像源
|
||||
|
||||
停止 Colima
|
||||
|
||||
```shell
|
||||
colima stop
|
||||
```
|
||||
|
||||
编辑 Colima 配置文件
|
||||
|
||||
```shell
|
||||
code ~/.colima/default/colima.yaml
|
||||
```
|
||||
|
||||
在文件中找到 `docker: {}` 这个部分,添加或修改 `registry-mirrors` 字段,如下所示。如果文件里没有 `docker:` 部分,您可以手动在文件末尾添加。
|
||||
|
||||
```yaml
|
||||
# ... colima.yaml 文件中的其他配置 ...
|
||||
|
||||
# 添加或修改 docker 部分
|
||||
docker:
|
||||
registry-mirrors:
|
||||
- https://docker.m.daocloud.io
|
||||
- https://docker.imgdb.de
|
||||
- https://docker-0.unsee.tech
|
||||
- https://docker.hlmirror.com
|
||||
- https://docker.1ms.run
|
||||
- https://cjie.eu.org
|
||||
- https://func.ink
|
||||
- https://lispy.org
|
||||
- https://docker.xiaogenban1993.com
|
||||
|
||||
# 您可以添加多个,按顺序尝试
|
||||
|
||||
# ... colima.yaml 文件中的其他配置 ...
|
||||
```
|
||||
|
||||
修改后保存文件。
|
||||
|
||||
重新启动 Colima
|
||||
|
||||
```shell
|
||||
colima start
|
||||
```
|
||||
|
||||
Colima 在启动时会读取配置,并自动生成虚拟机内的 `/etc/docker/daemon.json` 文件。
|
||||
|
||||
验证配置是否生效
|
||||
|
||||
```shell
|
||||
# 进入 Colima 虚拟机
|
||||
colima ssh
|
||||
|
||||
# 在虚拟机内,执行 docker info 命令并过滤出镜像源信息
|
||||
docker info | grep "Registry Mirrors" -A 2
|
||||
```
|
||||
|
||||
如果看到类似下面的输出,就证明配置成功了:
|
||||
|
||||
```shell
|
||||
Registry Mirrors:
|
||||
https://docker.m.daocloud.io/
|
||||
https://docker.imgdb.de/
|
||||
```
|
||||
|
||||
|
||||
|
||||
## SVN
|
||||
|
||||
### 安装
|
||||
|
||||
```shell
|
||||
brew install svn
|
||||
```
|
||||
|
||||
|
||||
|
||||
# 常用软件
|
||||
|
||||
## iTerm2
|
||||
|
||||
### 安装
|
||||
|
||||
|
||||
|
||||
### 配置
|
||||
|
||||
#### 主题
|
||||
|
||||
在当前用户目录`~`下新建一个专门用于存放配置文件的文件夹,例如 `~/.dotfiles`
|
||||
|
||||
```shell
|
||||
mkdir -p ~/.dotfiles
|
||||
```
|
||||
|
||||
然后新建存放`iTerm2`的配置文件目录,并在其中创建存放主题的目录
|
||||
|
||||
```shell
|
||||
mkdir -p ~/.dotfiles/iTerm-Settings/themes
|
||||
```
|
||||
|
||||
拉取主题文件,例如`dracula`
|
||||
|
||||
```shell
|
||||
git clone https://github.com/dracula/iterm.git ~/.dotfiles/iTerm-Settings/themes/dracula
|
||||
```
|
||||
|
||||
## Visual Studio Code
|
||||
|
||||
### 配置
|
||||
|
||||
#### `Code` 命令
|
||||
|
||||
1. 打开 Visual Studio Code
|
||||
2. 打开命令面板 (Command Palette)
|
||||
使用快捷键 `⌘ + Shift + P` (Command + Shift + P) 来打开命令面板。这是 VS Code 中最核心的功能入口。
|
||||
3. 运行安装命令
|
||||
在弹出的命令面板输入框中,输入 `shell` 或者 `code`,它会自动筛选出相关命令。 找到并选择 **`Shell Command: Install 'code' command in PATH`** 这一项,然后按回车。
|
||||
4. 输入密码授权
|
||||
系统可能会提示您输入当前 Mac 用户的登录密码,因为它需要权限在 `/usr/local/bin/` 目录下创建一个符号链接。按提示输入密码后回车即可。 如果成功,您会看到一个小的确认弹窗。
|
||||
5. 重启终端
|
||||
关闭当前正在使用的所有终端窗口(无论是系统自带的 Terminal 还是 iTerm2),然后重新打开一个新的终端窗口。 这样做是为了让终端重新加载 `PATH` 环境变量,从而识别到新安装的 `code` 命令。
|
||||
|
||||
# 系统设置
|
||||
|
||||
## 键盘
|
||||
|
||||
### 关闭 首字母自动大写 功能
|
||||
|
||||
键盘 > 文字输入 > 输入法(ABC 和 简体拼音)> 编辑 > 关闭 自动大写字词的首字母
|
||||
|
||||
## 隐私与安全性
|
||||
|
||||
### 允许安装任何来源的应用程序
|
||||
|
||||
默认是不显示的,需通过终端,打开任何来源选项的显示
|
||||
|
||||
```shell
|
||||
sudo spctl --master-disable
|
||||
```
|
||||
|
||||
@@ -10,106 +10,106 @@ tags:
|
||||
|
||||
默认选中「Try or Install Ubuntu Server」安装选项,回车(或等待 30 秒后),等待系统镜像自检并进行安装初始化。
|
||||
|
||||

|
||||

|
||||
|
||||
### 选择语言:English
|
||||
|
||||

|
||||

|
||||
|
||||
### 键盘默认:English
|
||||
|
||||

|
||||

|
||||
|
||||
### 安装类型:Ubuntu Server
|
||||
|
||||
选择默认第一个(会自带一些组件,方便使用)
|
||||
|
||||

|
||||

|
||||
|
||||
### 网络配置
|
||||
|
||||
使用 DHCP 或者 静态IP (建议这里设置好 静态IP,如果选择 DHCP,则在此界面直接选择Done 后即可)
|
||||
|
||||

|
||||

|
||||
|
||||
静态IP 选择 Edit IPv4
|
||||
|
||||

|
||||

|
||||
|
||||
然后选择 Manual
|
||||
|
||||

|
||||

|
||||
|
||||

|
||||

|
||||
|
||||
### 代理配置
|
||||
|
||||
**Configure proxy配置页面的Proxy address无需配置**
|
||||
|
||||

|
||||

|
||||
|
||||
### 镜像源配置
|
||||
|
||||
默认清华源
|
||||
|
||||

|
||||

|
||||
|
||||
### 安装磁盘配置
|
||||
|
||||
**选择安装磁盘,直接回车默认自动分配,需要手动分区的话选择 [custom storage layout]**
|
||||
|
||||

|
||||

|
||||
|
||||
选择 **custom storage layout**
|
||||
|
||||

|
||||

|
||||
|
||||

|
||||

|
||||
|
||||
首先分配swap分区:一般基于物理内存的 2-4倍
|
||||
|
||||

|
||||

|
||||
|
||||
/boot 分区,一般2G足以
|
||||
|
||||
/ 根分区,分配剩余空间
|
||||
|
||||

|
||||

|
||||
|
||||
### 设置计算机名及用户名
|
||||
|
||||

|
||||

|
||||
|
||||
### 是否升级 Ubuntu Pro
|
||||
|
||||
直接默认跳过即可
|
||||

|
||||

|
||||
|
||||
### 安装 OpenSSH 服务
|
||||
|
||||

|
||||

|
||||
|
||||
### 选择预置环境
|
||||
|
||||
按需选取,不需要则直接选择 Done 回车继续
|
||||
|
||||

|
||||

|
||||
|
||||
安装系统中
|
||||
|
||||

|
||||

|
||||
|
||||
安装完成后重启即可
|
||||
|
||||

|
||||

|
||||
|
||||
重启完成,进入系统
|
||||
|
||||

|
||||

|
||||
|
||||
## 配置网络
|
||||
|
||||

|
||||

|
||||
|
||||
```shell
|
||||
cd /etc/netplan
|
||||
@@ -130,17 +130,17 @@ network:
|
||||
|
||||
在VirtualBox中工具->网络中 增加仅主机(Host-Only)网络
|
||||
|
||||

|
||||

|
||||
|
||||
网卡如果要是DHCP就选自动配置网卡,否则手动分配就选手动配置网卡
|
||||
|
||||
如果选DHCP,还需要启动服务器
|
||||
|
||||

|
||||

|
||||
|
||||
配置好后,在对应虚拟机中,添加好网卡,连接方式选择仅主机(Host-Only)网络,名称选择刚刚在工具中配置的
|
||||
|
||||

|
||||

|
||||
|
||||
以上修改需要先重启虚拟机
|
||||
|
||||
@@ -173,6 +173,466 @@ sudo netplan apply
|
||||
|
||||
若不报错,则修改成功,再执行`ip a`查看网卡信息
|
||||
|
||||

|
||||

|
||||
|
||||
ip地址已经生效,可以在主机里 ping 一下
|
||||
|
||||
## 安装GUI
|
||||
|
||||
默认情况下,Ubuntu Server不包括图形用户界面(GUI)。GUI占用了用于面向服务器的任务的系统资源(内存和处理器)。但是,某些任务和应用程序在GUI环境中更易于管理并且可以更好地工作。
|
||||
|
||||
### 更新存储库和软件包
|
||||
|
||||
首先更新存储库和软件包列表:
|
||||
|
||||
```shell
|
||||
sudo apt-get update && sudo apt-get upgrade
|
||||
```
|
||||
|
||||
这样可以确保正在使用最新的软件更新。
|
||||
|
||||
接下来,安装**tasksel manager**实用程序:
|
||||
|
||||
```shell
|
||||
sudo apt install tasksel
|
||||
```
|
||||
|
||||
> **注意:** **Tasksel**是用于一次安装多个相关软件包的实用程序。有关更多详细信息,请参见[文档](https://help.ubuntu.com/community/Tasksel)。
|
||||
|
||||
### 选择一个显示管理器
|
||||
|
||||
显示管理器是启动显示服务器,启动桌面并管理用户身份验证的应用程序。默认的**GDM3**(与[KDE-Plasma一起使用](https://kde.org/plasma-desktop))是资源密集型显示管理器。如果需要节省系统资源,请考虑使用更浅的显示管理器,例如**SDDM**,**SLiM**或**LightDM**。
|
||||
|
||||
默认情况下,只有一个显示管理器可以管理服务器。仅当配置为管理其他服务器时,它们才能同时运行。本文假定您将使用单个默认显示管理器。
|
||||
|
||||
显示当前使用的显示管理器:
|
||||
|
||||
```shell
|
||||
cat /etc/X11/default-display-manager
|
||||
```
|
||||
|
||||
要安装特定的显示管理器,请使用**apt-get**程序包管理器:
|
||||
|
||||
要安装SLiM:
|
||||
|
||||
```shell
|
||||
sudo apt-get install slim
|
||||
```
|
||||
|
||||
要安装LightDM:
|
||||
|
||||
```shell
|
||||
sudo apt-get install lightdm
|
||||
```
|
||||
|
||||
该**SDDM**显示管理器可从安装**中的tasksel** KDE的安装过程中的菜单。
|
||||
|
||||
切换显示管理器
|
||||
|
||||
```shell
|
||||
sudo dpkg-reconfigure gdm3
|
||||
```
|
||||
|
||||
|
||||
|
||||
### 选择服务器的GUI
|
||||
|
||||
GNOME是大多数Ubuntu安装的默认GUI,并且(宽松地)基于Apple生态系统。
|
||||
|
||||
KDE是另一种流行的GUI,(宽松地)基于Microsoft生态系统。如果要具有常规Ubuntu系统的外观,请选择以下桌面环境之一。
|
||||
|
||||
#### GNOME
|
||||
|
||||
要安装GNOME,请首先启动**taskel**:
|
||||
|
||||
```
|
||||
tasksel
|
||||
```
|
||||
|
||||
将会启动一个彩色界面。使用箭头键向下滚动列表,找到**Ubuntu桌面**。
|
||||
|
||||
使用**空格**键将其选中`ubuntu-desktop`,然后按**Tab**键选择底部的**确定**,然后按**Enter键**。
|
||||
|
||||
> 要使用`ubuntu-desktop`,需事先安装好,通过 sudo apt install -y ubuntu-desktop
|
||||
|
||||
系统将安装软件并重新引导,为您提供由默认显示管理器生成的图形登录屏幕。在我们的例子中是SLiM。
|
||||
|
||||
输入您的**登录凭据**。如果您安装了多个接口,请使用**F1**在GUI之间切换。
|
||||
|
||||
卸载ubuntu-desktop
|
||||
|
||||
```shell
|
||||
sudo apt remove -y --purge ubuntu-desktop
|
||||
sudo apt-get autoremove
|
||||
sudo snap remove thunderbird
|
||||
sudo snap remove gnome-42-2204
|
||||
sudo snap remove firefox
|
||||
sudo snap remove gtk-common-themes
|
||||
sudo apt-get remove gnome-tweak-tool
|
||||
sudo apt-get remove gnome-shell
|
||||
```
|
||||
|
||||
|
||||
|
||||
#### KDE Plasma
|
||||
|
||||
要安装KDE Plasma,请使用以下Linux命令:
|
||||
|
||||
```
|
||||
sudo apt-get install kde-plasma-desktop
|
||||
```
|
||||
|
||||
在安装过程中可能会提示您选择默认显示管理器。使用箭头键进行选择,然后按**Enter**。
|
||||
|
||||
使用以下命令启动KDE Plasma:
|
||||
|
||||
```
|
||||
sudo service display_manager start
|
||||
```
|
||||
|
||||
代替*display_manager,* 输入已安装的显示管理器的名称(例如SLiM,lightDM,SDDM)。输入您的凭据并登录。
|
||||
|
||||
> **注意:**这些传统的Ubuntu Server GUI应用程序需要大量的系统资源。它们可能会影响服务器的功能。如果需要最大程度地利用服务器资源,请考虑下面列出的较轻的GUI应用程序之一。
|
||||
|
||||
#### Mate 服务器核心桌面
|
||||
|
||||
**Mate**是一种流行的轻量级图形界面。通过执行以下命令进行安装:
|
||||
|
||||
```
|
||||
sudo tasksel install ubuntu-mate-core
|
||||
```
|
||||
|
||||
等待taskel完成操作。完成后,使用以下命令启动桌面界面:
|
||||
|
||||
```
|
||||
sudo service display_manager start
|
||||
```
|
||||
|
||||
代替*display_manager,* 输入已安装的显示管理器的名称(例如SLiM,lightDM,SDDM)。系统将提示您登录。
|
||||
|
||||
要退出GUI,请打开命令行并输入:
|
||||
|
||||
```
|
||||
sudo service display_manager stop
|
||||
```
|
||||
|
||||
> **注意**:您可能需要按**Ctrl-Alt-F1**才能返回到服务器的命令行界面。另请注意,此过程会自动安装并使用**lightdm**显示管理器。
|
||||
|
||||
#### Lubuntu核心服务器桌面
|
||||
|
||||
Lubuntu是一个非常轻量级的GUI。如果需要图形界面,但要最大程度地减少对系统内存和处理器的影响,请使用此应用程序。
|
||||
|
||||
要安装Lubuntu,请输入以下内容:
|
||||
|
||||
```
|
||||
sudo tasksel install lubuntu-core
|
||||
```
|
||||
|
||||
或者,您可以使用以下命令从**taskel**菜单安装:
|
||||
|
||||
```
|
||||
tasksel
|
||||
```
|
||||
|
||||
使用箭头键突出显示要使用的Lubuntu GUI。按**空格**键进行选择,然后按**Tab键**至**OK**按钮,然后按**Enter键**。
|
||||
|
||||
使用以下命令启动GUI:
|
||||
|
||||
```
|
||||
sudo service display_manager start
|
||||
```
|
||||
|
||||
通过打开终端窗口并输入以下内容来退出GUI:
|
||||
|
||||
```
|
||||
sudo service display_manager stop
|
||||
```
|
||||
|
||||
#### Xubuntu服务器核心桌面
|
||||
|
||||
Xubuntu是使用Xfce桌面环境的Ubuntu的派生版本。
|
||||
|
||||
通过输入以下命令安装Xubuntu:
|
||||
|
||||
```
|
||||
sudo tasksel install xubuntu-core
|
||||
```
|
||||
|
||||
输入以下命令启动它:
|
||||
|
||||
```
|
||||
sudo service display_manager start
|
||||
```
|
||||
|
||||
#### Xfce桌面
|
||||
|
||||
Xfce桌面环境可以单独使用。它被设计为响应迅速,轻巧且用户友好。
|
||||
|
||||
使用以下命令安装Xfce:
|
||||
|
||||
```
|
||||
sudo apt-get install xfce4 slim
|
||||
```
|
||||
|
||||
输入以下命令启动Xfce:
|
||||
|
||||
```
|
||||
sudo service slim start
|
||||
```
|
||||
|
||||
> **注意:** Xfce GUI仅与SLiM显示管理器兼容。
|
||||
|
||||
### 在GUI之间切换
|
||||
|
||||
如果安装了多个GUI,则可以选择要使用的GUI。启动显示管理器后,将提示您登录。但是,该屏幕还允许您选择要启用的GUI。
|
||||
|
||||
通过按**F1**在GUI之间切换。该界面将在会话(或GUI)之间切换。切换到所选的GUI后登录。
|
||||
|
||||
### 关闭与打开GUI
|
||||
|
||||
#### 关闭
|
||||
|
||||
```shell
|
||||
sudo systemctl set-default multi-user.target
|
||||
sudo reboot
|
||||
```
|
||||
|
||||
#### 打开
|
||||
|
||||
```shell
|
||||
sudo systemctl set-default graphical.target
|
||||
sudo reboot
|
||||
```
|
||||
|
||||
## 远程桌面配置
|
||||
|
||||
### RDP
|
||||
|
||||
Windows 带有一个非常方便的功能,称为远程桌面连接,它使用 RDP 协议远程连接 PC。虽然在建立从 Windows 到 Windows 系统的远程桌面连接时使用起来非常容易,但对于 Linux 系统来说就不一样了。这是因为Linux默认没有安装RDP协议。在这种情况下,我们必须在 Linux 系统上手动执行一些配置来启用 RDP,在本指南中我们知道如何做到这一点。
|
||||
|
||||
什么是XRDP?
|
||||
|
||||
> XRDP 是一个免费的开源程序,是 Microsoft RDP(远程桌面协议)的实现,可通过 GUI 轻松远程访问 Linux 系统。使用 XRDP,可以登录到远程 Linux 计算机并创建一个真实的桌面会话,就像您登录到本地计算机一样。
|
||||
|
||||
#### 执行存储库更新
|
||||
|
||||
```shell
|
||||
sudo apt update
|
||||
```
|
||||
|
||||
#### 在 Ubuntu 24.04.2 LTS 上安装XRDP
|
||||
|
||||
我们知道 Ubuntu 没有像 Windows 操作系统那样安装 RDP,因此,我们需要在我们的 Linux 系统上安装 RDP 的开源实现 XRDP。好在我们不需要添加任何第三方存储库,因为它可以使用系统默认安装。
|
||||
|
||||
```shell
|
||||
sudo apt install xrdp
|
||||
```
|
||||
|
||||
#### 启动并启用 XRDP 服务
|
||||
|
||||
要在系统启动时自动启动并启用 XRDP 服务,请使用给定的命令:
|
||||
|
||||
启动它:
|
||||
|
||||
```shell
|
||||
sudo systemctl start xrdp
|
||||
```
|
||||
|
||||
开机并启用它:
|
||||
|
||||
```shell
|
||||
sudo systemctl enable xrdp
|
||||
```
|
||||
|
||||
检查状态:
|
||||
|
||||
```shell
|
||||
systemctl status xrdp
|
||||
```
|
||||
|
||||
#### 在防火墙中放行3389端口
|
||||
|
||||
要让网络中的其他系统通过 RDP 远程访问 Ubuntu 24.04.2 LTS,请在系统防火墙上放行端口号 3389。
|
||||
|
||||
```shell
|
||||
sudo ufw allow from any to any port 3389 proto tcp
|
||||
```
|
||||
|
||||

|
||||
|
||||
**接下来**,查看你的 Ubuntu 系统的 IP 地址,并在某处记下它。在您的终端上运行:
|
||||
|
||||
```shell
|
||||
ip a
|
||||
```
|
||||
|
||||
#### KDE Plasma解决XRDP无法连接的问题
|
||||
|
||||
> [Installing KDE Plasma and XRDP Service on Remote Ubuntu 22](https://www.vps-mart.com/blog/install-kde-plasma-and-xrdp-service-on-remote-ubuntu)
|
||||
|
||||
通过XRDP登录时启动KDE等离子会话。 CAT命令用于创建具有指定环境变量的.xsessionrc文件。执行这些命令后,将使用指定内容创建或覆盖〜/.xsession和〜/.xsessionRC文件。这些文件通常在X会话启动过程中用于设置环境变量并定义要执行的启动命令或脚本。
|
||||
|
||||
```shell
|
||||
echo "/usr/bin/startplasma-x11" > ~/.xsession
|
||||
D=/usr/share/plasma:/usr/local/share:/usr/share:/var/lib/snapd/desktop
|
||||
C=/etc/xdg/xdg-plasma:/etc/xdg
|
||||
C=${C}:/usr/share/kubuntu-default-settings/kf5-settings
|
||||
cat < ~/.xsessionrc
|
||||
export XDG_SESSION_DESKTOP=KDE
|
||||
export XDG_DATA_DIRS=${D}
|
||||
export XDG_CONFIG_DIRS=${C}
|
||||
EOF
|
||||
```
|
||||
|
||||
重启 XRDP服务
|
||||
|
||||
```shell
|
||||
systemctl restart xrdp
|
||||
```
|
||||
|
||||
## 更换时区
|
||||
|
||||
### 查看当前时区:
|
||||
|
||||
```shell
|
||||
timedatectl
|
||||
```
|
||||
|
||||
类似输出
|
||||
|
||||
```shell
|
||||
Local time: Mon 2025-07-21 01:05:37 UTC
|
||||
Universal time: Mon 2025-07-21 01:05:37 UTC
|
||||
RTC time: Mon 2025-07-21 01:05:37
|
||||
Time zone: Etc/UTC (UTC, +0000)
|
||||
System clock synchronized: yes
|
||||
NTP service: active
|
||||
RTC in local TZ: no
|
||||
|
||||
```
|
||||
|
||||
### 列出所有可用时区:
|
||||
|
||||
```shell
|
||||
timedatectl list-timezones
|
||||
```
|
||||
|
||||
时区太多了,可以使用管道过滤查找你所在的城市,例如:
|
||||
|
||||
```shell
|
||||
timedatectl list-timezones | grep Shanghai
|
||||
```
|
||||
|
||||
输出:
|
||||
```shell
|
||||
Asia/Shanghai
|
||||
```
|
||||
|
||||
### 设置新的时区:
|
||||
|
||||
例如,将时区设置为 **上海(北京时间)** :
|
||||
|
||||
```shell
|
||||
sudo timedatectl set-timezone Asia/Shanghai
|
||||
```
|
||||
|
||||
#### 再次查看时区确认是否更改成功:
|
||||
|
||||
```shell
|
||||
timedatectl
|
||||
```
|
||||
|
||||
## snap包管理器
|
||||
|
||||
> [Linux snap 命令 | 菜鸟教程](https://www.runoob.com/linux/linux-comm-snap.html)
|
||||
|
||||
### 安装snap软件
|
||||
|
||||
```shell
|
||||
sudo snap install hello-world
|
||||
```
|
||||
|
||||
### 卸载snap软件
|
||||
|
||||
```shell
|
||||
sudo snap remove hello-world
|
||||
```
|
||||
|
||||
### 查看已安装的snap软件
|
||||
|
||||
```shell
|
||||
snap list
|
||||
```
|
||||
|
||||
|
||||
|
||||
### 解决snap包管理器下载报错 x509: certificate signed by unknown authority
|
||||
|
||||
#### 代理方式
|
||||
|
||||
```shell
|
||||
sudo snap set system proxy.https="http://127.0.0.1:7890"
|
||||
sudo snap set system proxy.http="http://127.0.0.1:7890"
|
||||
```
|
||||
|
||||
然后可以正常安装:
|
||||
|
||||
```shell
|
||||
sudo snap install hello-world
|
||||
```
|
||||
|
||||
## 禁止自动挂起
|
||||
|
||||
```shell
|
||||
Broadcast message from user@ubuntu-ai-dev-server (Tue 2025-07-22 15:34:31 CST):
|
||||
|
||||
The system will suspend now!
|
||||
```
|
||||
|
||||
### 解决方式
|
||||
|
||||
```shell
|
||||
sudo vim /etc/systemd/logind.conf
|
||||
```
|
||||
|
||||
将里面的
|
||||
|
||||
```shell
|
||||
IdleAction=suspend
|
||||
```
|
||||
|
||||
改为
|
||||
|
||||
```shell
|
||||
IdleAction=ignore
|
||||
```
|
||||
|
||||
# apt包管理器
|
||||
|
||||
## 安装Fastfetch
|
||||
|
||||
**添加 Fastfetch PPA:**
|
||||
|
||||
```Bash
|
||||
sudo add-apt-repository ppa:zhangsongcui3371/fastfetch
|
||||
```
|
||||
|
||||
这条命令会提示并按回车确认添加 PPA。
|
||||
|
||||
**更新软件包列表:** 添加 PPA 后,需要更新软件包列表,以便系统能够识别新添加的软件源。
|
||||
|
||||
```Bash
|
||||
sudo apt update
|
||||
```
|
||||
|
||||
**安装 Fastfetch:** 现在,可以安装 Fastfetch 了:
|
||||
|
||||
```Bash
|
||||
sudo apt install fastfetch
|
||||
```
|
||||
|
||||
**运行 Fastfetch:** 安装完成后,可以在终端中输入 `fastfetch` 来运行它:
|
||||
|
||||
```Bash
|
||||
fastfetch
|
||||
```
|
||||
|
||||
|
After Width: | Height: | Size: 7.5 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 18 KiB |
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 9.6 KiB |
|
After Width: | Height: | Size: 9.6 KiB |
|
After Width: | Height: | Size: 10 KiB |
|
After Width: | Height: | Size: 49 KiB |
|
After Width: | Height: | Size: 8.8 KiB |
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 9.8 KiB |
|
After Width: | Height: | Size: 10 KiB |
|
After Width: | Height: | Size: 13 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 9.0 KiB |
|
After Width: | Height: | Size: 8.9 KiB |
|
After Width: | Height: | Size: 7.9 KiB |
|
After Width: | Height: | Size: 21 KiB |
|
After Width: | Height: | Size: 21 KiB |
|
After Width: | Height: | Size: 21 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 74 KiB |
|
After Width: | Height: | Size: 68 KiB |
|
After Width: | Height: | Size: 47 KiB |
|
After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 129 KiB |
@@ -0,0 +1,353 @@
|
||||
---
|
||||
title: 大数据
|
||||
date: 2025-08-03 22:53:51
|
||||
tags:
|
||||
---
|
||||
|
||||
# Apache Doris
|
||||
|
||||
## 简介
|
||||
|
||||
## 安装
|
||||
|
||||
### Docker Compose 方式
|
||||
|
||||
> [Quick Start - Apache Doris](https://doris.apache.org/docs/dev/gettingStarted/quick-start)
|
||||
|
||||
新建用于Docker Compose 集群编排启动目录`mkdir -p /OLAP/doris`
|
||||
|
||||
```bash
|
||||
mkdir -p /OLAP/doris
|
||||
```
|
||||
|
||||
编写启动脚本`start-doris.sh`
|
||||
|
||||
> https://doris.apache.org/files/start-doris.sh
|
||||
|
||||
```sh
|
||||
#!/bin/bash
|
||||
|
||||
# Default version
|
||||
DORIS_QUICK_START_VERSION="2.1.9"
|
||||
|
||||
# Parse parameters
|
||||
while getopts "v:" opt; do
|
||||
case $opt in
|
||||
v) DORIS_QUICK_START_VERSION="$OPTARG"
|
||||
;;
|
||||
\?) echo "Invalid option: -$OPTARG" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
# Check system type
|
||||
OS_TYPE=$(uname -s)
|
||||
if [[ "$OS_TYPE" != "Linux" && "$OS_TYPE" != "Darwin" ]]; then
|
||||
echo "Error: Unsupported operating system [$OS_TYPE], only Linux and Mac are supported"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check Docker environment
|
||||
if ! command -v docker &> /dev/null; then
|
||||
echo "Error: Docker environment not detected, please install Docker first"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check docker-compose
|
||||
COMPOSE_CMD=""
|
||||
if command -v docker-compose &> /dev/null; then
|
||||
COMPOSE_CMD="docker-compose"
|
||||
elif docker compose version &> /dev/null; then
|
||||
COMPOSE_CMD="docker compose"
|
||||
else
|
||||
echo "Error: docker-compose plugin or docker-compose command is required"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Generate docker-compose configuration for corresponding system
|
||||
if [[ "$OS_TYPE" == "Linux" ]]; then
|
||||
cat > docker-compose-doris.yaml <<EOF
|
||||
version: "3"
|
||||
services:
|
||||
fe:
|
||||
image: apache/doris:fe-${DORIS_QUICK_START_VERSION}
|
||||
hostname: fe
|
||||
environment:
|
||||
- FE_SERVERS=fe1:127.0.0.1:9010
|
||||
- FE_ID=1
|
||||
network_mode: host
|
||||
volumes:
|
||||
- /mnt/app/doris/fe/doris-meta/:/opt/apache-doris/fe/doris-meta/
|
||||
- /mnt/app/doris/fe/log/:/opt/apache-doris/fe/log/
|
||||
be:
|
||||
image: apache/doris:be-${DORIS_QUICK_START_VERSION}
|
||||
hostname: be
|
||||
environment:
|
||||
- FE_SERVERS=fe1:127.0.0.1:9010
|
||||
- BE_ADDR=127.0.0.1:9050
|
||||
depends_on:
|
||||
- fe
|
||||
network_mode: host
|
||||
volumes:
|
||||
- /mnt/app/doris/be/storage/:/opt/apache-doris/be/storage/
|
||||
- /mnt/app/doris/be/script/:/docker-entrypoint-initdb.d/
|
||||
EOF
|
||||
else # Mac system
|
||||
cat > docker-compose-doris.yaml <<EOF
|
||||
version: "3"
|
||||
networks:
|
||||
custom_network:
|
||||
driver: bridge
|
||||
ipam:
|
||||
config:
|
||||
- subnet: 172.20.80.0/24
|
||||
|
||||
services:
|
||||
fe:
|
||||
image: apache/doris:fe-${DORIS_QUICK_START_VERSION}
|
||||
hostname: fe
|
||||
ports:
|
||||
- 8030:8030
|
||||
- 9030:9030
|
||||
- 9010:9010
|
||||
environment:
|
||||
- FE_SERVERS=fe1:172.20.80.2:9010
|
||||
- FE_ID=1
|
||||
networks:
|
||||
custom_network:
|
||||
ipv4_address: 172.20.80.2
|
||||
|
||||
be:
|
||||
image: apache/doris:be-${DORIS_QUICK_START_VERSION}
|
||||
hostname: be
|
||||
ports:
|
||||
- 8040:8040
|
||||
- 9050:9050
|
||||
environment:
|
||||
- FE_SERVERS=fe1:172.20.80.2:9010
|
||||
- BE_ADDR=172.20.80.3:9050
|
||||
depends_on:
|
||||
- fe
|
||||
networks:
|
||||
custom_network:
|
||||
ipv4_address: 172.20.80.3
|
||||
EOF
|
||||
fi
|
||||
|
||||
# Start services
|
||||
$COMPOSE_CMD -f docker-compose-doris.yaml up -d
|
||||
|
||||
echo "Doris cluster started successfully, version: ${DORIS_QUICK_START_VERSION}"
|
||||
echo "You can manage the cluster using the following commands:"
|
||||
echo " Stop cluster: $COMPOSE_CMD -f docker-compose-doris.yaml down"
|
||||
echo " View logs: $COMPOSE_CMD -f docker-compose-doris.yaml logs -f"
|
||||
echo " Connect to cluster: mysql -uroot -P9030 -h127.0.0.1"
|
||||
|
||||
# Display connection information based on system type
|
||||
if [[ "$OS_TYPE" == "Linux" ]]; then
|
||||
echo -e "\nAccess FE/BE http ports (8030, 8040) using the following addresses (Linux system):"
|
||||
echo " http://127.0.0.1:8030"
|
||||
echo " http://127.0.0.1:8040"
|
||||
elif [[ "$OS_TYPE" == "Darwin" ]]; then
|
||||
echo -e "\nAccess FE/BE http ports (8030, 8040) using the following addresses (Mac system):"
|
||||
echo " http://docker.for.mac.localhost:8030"
|
||||
echo " http://docker.for.mac.localhost:8040"
|
||||
echo "Note: If access fails, try using 127.0.0.1 address:"
|
||||
echo " http://127.0.0.1:8030"
|
||||
echo " http://127.0.0.1:8040"
|
||||
fi
|
||||
```
|
||||
|
||||
赋予权限
|
||||
|
||||
```bash
|
||||
chmod 755 start-doris.sh
|
||||
```
|
||||
|
||||
启动集群
|
||||
|
||||
```bash
|
||||
./start-doris.sh
|
||||
```
|
||||
|
||||
可以指定启动的版本通过`-v`参数,比如:
|
||||
|
||||
```bash
|
||||
./start-doris.sh -v 2.1.8
|
||||
```
|
||||
|
||||
使用MySQL客户端连接到集群并检查集群状态
|
||||
|
||||
```bash
|
||||
## Check the FE status to ensure that both the Join and Alive columns are true.
|
||||
mysql -uroot -P9030 -h127.0.0.1 -e 'SELECT `host`, `join`, `alive` FROM frontends()'
|
||||
+-----------+------+-------+
|
||||
| host | join | alive |
|
||||
+-----------+------+-------+
|
||||
| 127.0.0.1 | true | true |
|
||||
+-----------+------+-------+
|
||||
|
||||
## Check the BE status to ensure that the Alive column is true.
|
||||
mysql -uroot -P9030 -h127.0.0.1 -e 'SELECT `host`, `alive` FROM backends()'
|
||||
+-----------+-------+
|
||||
| host | alive |
|
||||
+-----------+-------+
|
||||
| 127.0.0.1 | 1 |
|
||||
+-----------+-------+
|
||||
|
||||
```
|
||||
|
||||
|
||||
|
||||
### 配置
|
||||
|
||||
#### Linux系统环境配置(所有节点均需配置)
|
||||
|
||||
##### 调大文件操作配置
|
||||
|
||||
```bash
|
||||
vim /etc/security/limits.conf
|
||||
```
|
||||
|
||||
在文件最后添加下面几行信息(注意 * 也要复制进去)
|
||||
|
||||
```conf
|
||||
* soft nofile 65536
|
||||
* hard nofile 65536
|
||||
* soft nproc 65536
|
||||
* hard nproc 65536
|
||||
```
|
||||
|
||||
可使用以下命令直接追加到配置文件内
|
||||
|
||||
```bash
|
||||
echo "* soft nofile 65536" >> /etc/security/limits.conf
|
||||
echo "* hard nofile 65536" >> /etc/security/limits.conf
|
||||
echo "* soft nproc 65536" >> /etc/security/limits.conf
|
||||
echo "* hard nproc 65536" >> /etc/security/limits.conf
|
||||
```
|
||||
|
||||
保存完成需`reboot`,也可临时生效,免重启
|
||||
|
||||
```bash
|
||||
ulimit -n 65536
|
||||
```
|
||||
|
||||
# Datax
|
||||
|
||||
## MySQL离线同步至Apache Doris
|
||||
|
||||
### 单表同步
|
||||
|
||||
新建配置文件`mysql_2_doris_t_base_material.json`
|
||||
|
||||
```json
|
||||
{
|
||||
"job": {
|
||||
"setting": {
|
||||
"speed": {
|
||||
"channel": 1
|
||||
}
|
||||
},
|
||||
"content": [
|
||||
{
|
||||
"reader": {
|
||||
"name": "mysqlreader",
|
||||
"parameter": {
|
||||
"username": "root",
|
||||
"password": "123456",
|
||||
"column": [
|
||||
"ID", "PID", "CODE", "SHORTCODE", "NAME", "FULLNAME",
|
||||
"ISDETAIL", "CHILDCOUNT", "PYCODE", "LVL", "FLAG", "MODEL",
|
||||
"ISSTANDARD", "AUXCLASSID", "ERPCLSID", "UNITGROUPID", "UNITID",
|
||||
"DEFAULTLOC", "SPID", "QTYDECIMAL", "SECINV", "MTYPE", "MVER",
|
||||
"MATERIAL", "FIRM", "FIRMORDER", "FACEDEAL", "SHAPESIZE",
|
||||
"TECHDESC", "UNITWEIGHT", "MCODE", "MCAT", "COSTITEM",
|
||||
"ORDERRECTOR", "POHIGHPRICE", "POHGHPRCMNYTYPE", "WWHGHPRC",
|
||||
"WWHGHPRCMNYTYPE", "SOLOWPRC", "SOLOWPRCMNYTYPE", "TRACK",
|
||||
"PRICEDECIMAL", "ACCTID", "SALEACCTID", "COSTACCTID",
|
||||
"DEFAULTROUTINGID", "DEFAULTWORKTYPEID", "PRODUCTPRINCIPAL",
|
||||
"PLANNER", "ISBACKFLUSH", "MRPCON", "MRPORDER", "CHARTNUMBER",
|
||||
"INSPECTIONLEVEL", "PROCHKMDE", "WWCHKMDE", "SOCHKMDE",
|
||||
"WTHDRWCHKMDE", "STKCHKMDE", "OTHERCHKMDE", "INSPECTIONPROJECT",
|
||||
"NAMEEN", "MODELEN", "HSNUMBER", "IMPOSTTAXRATE",
|
||||
"CONSUMETAXRATE", "STARTSERVICE", "MAKEFILE", "ISFIX",
|
||||
"TTERMOFSERVICE", "TTERMOFUSEFULTIME", "PRODUCTNO", "PARAMVALUE",
|
||||
"MEMO", "CDATE", "CUSERID", "CSTAFFNAME", "MDATE", "MUSERID",
|
||||
"MSTAFFNAME", "K_ID", "K_PID", "DDATE", "DUSERID", "DSTAFFNAME",
|
||||
"K_CODE", "AMODEL", "K_COSTITEM", "DWGSYMDESC", "SPDESC",
|
||||
"CDRATE", "GWEIGHT", "NWEIGHT", "L", "W", "H", "MSIZE",
|
||||
"K_COST", "BATCHAPPLICANT", "MATSLUGGISHSTATUS",
|
||||
"SLUGGISHEFFECTIVEDATE", "K_AUTO_ID", "FRATE", "K3CLOUDID"
|
||||
],
|
||||
"connection": [
|
||||
{
|
||||
"table": ["t_base_material"],
|
||||
"jdbcUrl": ["jdbc:mysql://192.168.6.35:3306/erp?useSSL=false&serverTimezone=Asia/Shanghai"],
|
||||
"selectedDatabase": "erp"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"writer": {
|
||||
"name": "doriswriter",
|
||||
"parameter": {
|
||||
"loadUrl": ["192.168.6.35:8040"],
|
||||
"username": "root",
|
||||
"password": "",
|
||||
"column": [
|
||||
"ID", "PID", "CODE", "SHORTCODE", "NAME", "FULLNAME",
|
||||
"ISDETAIL", "CHILDCOUNT", "PYCODE", "LVL", "FLAG", "MODEL",
|
||||
"ISSTANDARD", "AUXCLASSID", "ERPCLSID", "UNITGROUPID", "UNITID",
|
||||
"DEFAULTLOC", "SPID", "QTYDECIMAL", "SECINV", "MTYPE", "MVER",
|
||||
"MATERIAL", "FIRM", "FIRMORDER", "FACEDEAL", "SHAPESIZE",
|
||||
"TECHDESC", "UNITWEIGHT", "MCODE", "MCAT", "COSTITEM",
|
||||
"ORDERRECTOR", "POHIGHPRICE", "POHGHPRCMNYTYPE", "WWHGHPRC",
|
||||
"WWHGHPRCMNYTYPE", "SOLOWPRC", "SOLOWPRCMNYTYPE", "TRACK",
|
||||
"PRICEDECIMAL", "ACCTID", "SALEACCTID", "COSTACCTID",
|
||||
"DEFAULTROUTINGID", "DEFAULTWORKTYPEID", "PRODUCTPRINCIPAL",
|
||||
"PLANNER", "ISBACKFLUSH", "MRPCON", "MRPORDER", "CHARTNUMBER",
|
||||
"INSPECTIONLEVEL", "PROCHKMDE", "WWCHKMDE", "SOCHKMDE",
|
||||
"WTHDRWCHKMDE", "STKCHKMDE", "OTHERCHKMDE", "INSPECTIONPROJECT",
|
||||
"NAMEEN", "MODELEN", "HSNUMBER", "IMPOSTTAXRATE",
|
||||
"CONSUMETAXRATE", "STARTSERVICE", "MAKEFILE", "ISFIX",
|
||||
"TTERMOFSERVICE", "TTERMOFUSEFULTIME", "PRODUCTNO", "PARAMVALUE",
|
||||
"MEMO", "CDATE", "CUSERID", "CSTAFFNAME", "MDATE", "MUSERID",
|
||||
"MSTAFFNAME", "K_ID", "K_PID", "DDATE", "DUSERID", "DSTAFFNAME",
|
||||
"K_CODE", "AMODEL", "K_COSTITEM", "DWGSYMDESC", "SPDESC",
|
||||
"CDRATE", "GWEIGHT", "NWEIGHT", "L", "W", "H", "MSIZE",
|
||||
"K_COST", "BATCHAPPLICANT", "MATSLUGGISHSTATUS",
|
||||
"SLUGGISHEFFECTIVEDATE", "K_AUTO_ID", "FRATE", "K3CLOUDID"
|
||||
],
|
||||
"postSql": ["select count(1) from t_base_material"],
|
||||
"preSql": [],
|
||||
"flushInterval":30000,
|
||||
"connection": [
|
||||
{
|
||||
"jdbcUrl": "jdbc:mysql://192.168.6.35:9030/erp",
|
||||
"selectedDatabase": "erp",
|
||||
"table": ["t_base_material"]
|
||||
}
|
||||
],
|
||||
"loadProps": {
|
||||
"format": "json",
|
||||
"strip_outer_array":"true",
|
||||
"line_delimiter": "\\x02"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
执行任务
|
||||
|
||||
```bash
|
||||
cd datax
|
||||
python ./bin/datax.py mysql_2_doris_t_base_material.json
|
||||
```
|
||||
|
||||
@@ -125,30 +125,85 @@ alias ollama='ollama.exe'
|
||||
|
||||
## cuda-toolkit
|
||||
|
||||
### WSL安装
|
||||
|
||||
1. 下载 **CUDA Toolkit Installer**
|
||||
|
||||
```shell
|
||||
wget https://developer.download.nvidia.com/compute/cuda/12.8.1/local_installers/cuda-repo-rhel9-12-8-local-12.8.1_570.124.06-1.x86_64.rpm
|
||||
sudo rpm -i cuda-repo-rhel9-12-8-local-12.8.1_570.124.06-1.x86_64.rpm
|
||||
sudo dnf clean all
|
||||
sudo dnf -y install cuda-toolkit-12-8
|
||||
```
|
||||
### 下载 **CUDA Toolkit Installer**
|
||||
|
||||
#### AlmaLinux
|
||||
|
||||
```shell
|
||||
wget https://developer.download.nvidia.com/compute/cuda/12.8.1/local_installers/cuda-repo-rhel9-12-8-local-12.8.1_570.124.06-1.x86_64.rpm
|
||||
sudo rpm -i cuda-repo-rhel9-12-8-local-12.8.1_570.124.06-1.x86_64.rpm
|
||||
sudo dnf clean all
|
||||
sudo dnf -y install cuda-toolkit-12-8
|
||||
```
|
||||
|
||||
#### Ubuntu
|
||||
|
||||
```shell
|
||||
wget https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2404/x86_64/cuda-ubuntu2404.pin
|
||||
sudo mv cuda-ubuntu2404.pin /etc/apt/preferences.d/cuda-repository-pin-600
|
||||
wget https://developer.download.nvidia.com/compute/cuda/12.9.1/local_installers/cuda-repo-ubuntu2404-12-9-local_12.9.1-575.57.08-1_amd64.deb
|
||||
sudo dpkg -i cuda-repo-ubuntu2404-12-9-local_12.9.1-575.57.08-1_amd64.deb
|
||||
sudo cp /var/cuda-repo-ubuntu2404-12-9-local/cuda-*-keyring.gpg /usr/share/keyrings/
|
||||
sudo apt-get update
|
||||
sudo apt-get -y install cuda-toolkit-12-9
|
||||
```
|
||||
|
||||
### 安装 **Driver Installer**
|
||||
|
||||
#### 专有驱动
|
||||
|
||||
```shell
|
||||
sudo apt-get install -y cuda-drivers
|
||||
```
|
||||
|
||||
安装好后,需重启系统才可应用上。
|
||||
|
||||
```shell
|
||||
sudo reboot
|
||||
```
|
||||
|
||||
### 配置环境变量
|
||||
|
||||
```shell
|
||||
vim ~/.bashrc
|
||||
|
||||
# 文件末尾添加
|
||||
# cuda 10.2
|
||||
export CUDA_HOME=/usr/local/cuda
|
||||
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/cuda/lib64:/usr/local/cuda/extras/CUPTI/lib64
|
||||
export PATH=$PATH:$CUDA_HOME/bin
|
||||
```
|
||||
|
||||
## NVIDIA Container Toolkit
|
||||
|
||||
### 下载
|
||||
|
||||
#### With `apt`: Ubuntu, Debian
|
||||
|
||||
国内镜像源安装:
|
||||
|
||||
```shell
|
||||
curl -fsSL https://mirrors.ustc.edu.cn/libnvidia-container/gpgkey | sudo gpg --dearmor -o /usr/share/keyrings/nvidia-container-toolkit-keyring.gpg
|
||||
|
||||
curl -s -L https://mirrors.ustc.edu.cn/libnvidia-container/stable/deb/nvidia-container-toolkit.list | \
|
||||
sed 's#deb https://nvidia.github.io#deb [signed-by=/usr/share/keyrings/nvidia-container-toolkit-keyring.gpg] https://mirrors.ustc.edu.cn#g' | \
|
||||
sudo tee /etc/apt/sources.list.d/nvidia-container-toolkit.list
|
||||
|
||||
sudo apt-get update
|
||||
|
||||
sudo apt-get install -y nvidia-container-toolkit
|
||||
|
||||
nvidia-container-cli --version
|
||||
|
||||
sudo systemctl restart docker
|
||||
```
|
||||
|
||||
2. 配置环境变量
|
||||
```shell
|
||||
vim ~/.bashrc
|
||||
|
||||
# 文件末尾添加
|
||||
# cuda 10.2
|
||||
export CUDA_HOME=/usr/local/cuda
|
||||
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/cuda/lib64:/usr/local/cuda/extras/CUPTI/lib64
|
||||
export PATH=$PATH:$CUDA_HOME/bin
|
||||
```
|
||||
|
||||
|
||||
## nvidia-smi
|
||||
|
||||
> nvidia-smi是nvidia 的系统管理界面 ,其中smi是System management interface的缩写,它可以收集各种级别的信息,查看显存使用情况。此外, 可以启用和禁用 GPU 配置选项 (如 ECC 内存功能)。
|
||||
|
||||
```shell
|
||||
@@ -243,31 +298,31 @@ modelscope download --model deepseek-ai/DeepSeek-R1-Distill-Qwen-7B README.md --
|
||||
#### 指定下载单个文件(以'tokenizer.json'文件为例)
|
||||
|
||||
```
|
||||
modelscope download --model 'Qwen/Qwen2-7b' tokenizer.json
|
||||
modelscope download --model 'Qwen/Qwen2-7b' tokenizer.json
|
||||
```
|
||||
|
||||
#### 指定下载多个个文件
|
||||
|
||||
```
|
||||
modelscope download --model 'Qwen/Qwen2-7b' tokenizer.json config.json
|
||||
modelscope download --model 'Qwen/Qwen2-7b' tokenizer.json config.json
|
||||
```
|
||||
|
||||
#### 指定下载某些文件
|
||||
|
||||
```
|
||||
modelscope download --model 'Qwen/Qwen2-7b' --include '*.safetensors'
|
||||
modelscope download --model 'Qwen/Qwen2-7b' --include '*.safetensors'
|
||||
```
|
||||
|
||||
#### 过滤指定文件
|
||||
|
||||
```
|
||||
modelscope download --model 'Qwen/Qwen2-7b' --exclude '*.safetensors'
|
||||
modelscope download --model 'Qwen/Qwen2-7b' --exclude '*.safetensors'
|
||||
```
|
||||
|
||||
#### 指定下载cache_dir
|
||||
|
||||
```
|
||||
modelscope download --model 'Qwen/Qwen2-7b' --include '*.json' --cache_dir './cache_dir'
|
||||
modelscope download --model 'Qwen/Qwen2-7b' --include '*.json' --cache_dir './cache_dir'
|
||||
```
|
||||
|
||||
模型文件将被下载到`'cache_dir/Qwen/Qwen2-7b'`。
|
||||
@@ -275,13 +330,23 @@ modelscope download --model deepseek-ai/DeepSeek-R1-Distill-Qwen-7B README.md --
|
||||
#### 指定下载local_dir
|
||||
|
||||
```
|
||||
modelscope download --model 'Qwen/Qwen2-7b' --include '*.json' --local_dir './local_dir'
|
||||
modelscope download --model 'Qwen/Qwen2-7b' --include '*.json' --local_dir './local_dir'
|
||||
```
|
||||
|
||||
模型文件将被下载到`'./local_dir'`。
|
||||
|
||||
如果`cache_dir`和`local_dir`参数同时被指定,`local_dir`优先级高,`cache_dir`将被忽略。
|
||||
|
||||
### 环境变量配置
|
||||
|
||||
#### 默认下载目录
|
||||
|
||||
指定`modelscope`默认下载目录为`/AI/modelscope/hub`
|
||||
|
||||
```bash
|
||||
echo 'export MODELSCOPE_CACHE=/AI/modelscope/hub' >> ~/.bashrc
|
||||
```
|
||||
|
||||
# Anaconda
|
||||
|
||||
>
|
||||
@@ -290,7 +355,13 @@ modelscope download --model deepseek-ai/DeepSeek-R1-Distill-Qwen-7B README.md --
|
||||
|
||||
### minicoda
|
||||
|
||||
[安装 Miniconda — Anaconda 文档](https://docs.anaconda.net.cn/miniconda/install/)
|
||||
|
||||
```shell
|
||||
wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh
|
||||
bash ~/Miniconda3-latest-Linux-x86_64.sh
|
||||
source ~/.zshrc
|
||||
```
|
||||
|
||||
## 常用命令
|
||||
|
||||
@@ -409,7 +480,54 @@ modelscope download --model deepseek-ai/DeepSeek-R1-Distill-Qwen-7B README.md --
|
||||
conda init
|
||||
```
|
||||
|
||||
3.
|
||||
3. conda和pip换镜像源
|
||||
|
||||
修改conda,通过以下命令进行添加
|
||||
|
||||
```lua
|
||||
conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free/
|
||||
conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/main/
|
||||
conda config --set show_channel_urls yes
|
||||
```
|
||||
|
||||
修改后可以通过以下命令查看:
|
||||
|
||||
```armasm
|
||||
conda info
|
||||
```
|
||||
|
||||
下载试试:如果两都能看到下载源,那么就更改成功。
|
||||
|
||||
```mipsasm
|
||||
conda install
|
||||
```
|
||||
|
||||
##### Linux系统下:
|
||||
|
||||
linux系统下要到用户的文件夹下新建目录.pip,并在目录新建配置文件pip.conf
|
||||
|
||||
```bash
|
||||
mkdir ~/.pip
|
||||
cd ~/.pip
|
||||
vi pip.conf
|
||||
```
|
||||
|
||||
编辑内容:
|
||||
|
||||
```ini
|
||||
[global]
|
||||
index-url=https://pypi.tuna.tsinghua.edu.cn/simple
|
||||
[install]
|
||||
trusted-host=pypi.tuna.tsinghua.edu.cn
|
||||
disable-pip-version-check = true
|
||||
timeout = 6000
|
||||
```
|
||||
|
||||
下载试试:
|
||||
|
||||
```bash
|
||||
pip install
|
||||
```
|
||||
|
||||
# Jupyter Notebook
|
||||
|
||||
@@ -484,6 +602,65 @@ stdout_logfile=/var/log/supervisor/vLLM-Qwen-Qwen3-4B/out.log
|
||||
stopasgroup=true
|
||||
```
|
||||
|
||||
#### Docker
|
||||
|
||||
Docker Compose方式
|
||||
|
||||
```yaml
|
||||
services:
|
||||
vllm:
|
||||
image: 'vllm/vllm-openai:latest'
|
||||
container_name: vllm-Qwen-Qwen3-8B-AWQ
|
||||
restart: always
|
||||
environment:
|
||||
- 'TZ:Asia/Shanghai'
|
||||
- 'VLLM_USE_MODELSCOPE:True'
|
||||
- 'HF_HUB_OFFLINE:1'
|
||||
ports:
|
||||
- '8000:8000'
|
||||
volumes:
|
||||
- /home/user/modelscope:/root/.cache/modelscope
|
||||
- /etc/localtime:/etc/localtime:ro
|
||||
# 启用 NVIDIA GPU 支持
|
||||
# 在 Docker Desktop 上,可能只需要 'gpu',
|
||||
# 在 Linux 服务器上,通常是 'nvidia'
|
||||
# 你提供的命令行是 --runtime nvidia --gpus all
|
||||
# Docker Compose 对应的方式是:
|
||||
deploy:
|
||||
resources:
|
||||
reservations:
|
||||
devices:
|
||||
- driver: nvidia
|
||||
count: all # 或者指定具体的GPU数量,如 1, 2 等
|
||||
capabilities: [gpu] # 确保指定 GPU 能力
|
||||
# IPC 模式
|
||||
# ipc: host 允许容器与宿主机共享 IPC 命名空间,
|
||||
# 这在某些高性能场景下有用,例如共享内存。
|
||||
ipc: host
|
||||
# 容器启动时执行的命令和参数
|
||||
command:
|
||||
- --model
|
||||
- /root/.cache/modelscope/Qwen/Qwen3-8B-AWQ
|
||||
- --served_model_name
|
||||
- Qwen/Qwen3-4B # 你希望这个model暴露时的名称,如果不填默认为本地模型权重路径
|
||||
- --max_model_len
|
||||
- "8192" # 支持的最长上下文长度,根据显存大小自行匹配,注意这里需要是字符串
|
||||
# --api_key 参数在 vLLM 0.3.x 版本中可能不再是直接的命令行参数,
|
||||
# 而是通过环境变量 API_KEY 来设置的。
|
||||
# 我已将其移到 environment 部分。
|
||||
# 如果你的 vLLM 版本仍然支持命令行参数,请取消注释下一行:
|
||||
# - --api_key
|
||||
# - "<YOUR-API-KEY-HERE>"
|
||||
- --gpu_memory_utilization
|
||||
- "0.9"
|
||||
- --max-num-seqs
|
||||
- "128"
|
||||
- --api-key
|
||||
- token-abc123
|
||||
- --reasoning-parser
|
||||
- deepseek_r1
|
||||
```
|
||||
|
||||
|
||||
|
||||
# LLama.cpp
|
||||
@@ -817,3 +994,30 @@ print(f'Model is quantized and saved at "{quant_path}"')
|
||||
- **Hybrid-MoE**:折中方案,平衡性能与成本,需精细调优。
|
||||
|
||||
实际选型需结合**任务需求**、**硬件资源**和**工程能力**综合评估。对于大多数企业级应用,Hybrid-MoE可能是当前的最优解,而科研前沿更倾向于探索纯MoE的极限能力。
|
||||
|
||||
# Dify
|
||||
|
||||
## Dify 向量存储机制简述
|
||||
|
||||
在 Dify 中,文档数据(如知识库文档、FAQ、手册等)需要经过向量化处理,才能用于语义检索和问答增强。其核心处理流程如下图所示:
|
||||
|
||||
```
|
||||
文档(原始文本)
|
||||
↓
|
||||
Embedding(由 OpenAI, Hugging Face, etc. 提供)
|
||||
↓
|
||||
向量(高维 float 数组)
|
||||
↓
|
||||
Vector Store(默认为 Weaviate)
|
||||
↓
|
||||
Dify 查询时执行语义检索,返回匹配片段
|
||||
```
|
||||
|
||||
向量存储的作用
|
||||
|
||||
Dify 本身不负责存储嵌入向量,而是通过调用第三方向量数据库来管理这些向量。向量数据库的主要职责包括:
|
||||
|
||||
- 存储文本对应的向量数据(float 数组)
|
||||
- 为每条向量建立索引,支持高效近似/精确搜索
|
||||
- 提供语义检索 API(如 top-k 相似度查找)
|
||||
- 支持元数据管理(如 document_id, source, tags 等)
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
---
|
||||
title: 对象存储
|
||||
date: 2025-07-23 14:27:11
|
||||
tags:
|
||||
---
|
||||
|
||||
# RustFS
|
||||
|
||||
## 安装
|
||||
|
||||
### Docker
|
||||
|
||||
新建rustfs目录
|
||||
|
||||
```shell
|
||||
mkdir ~/rustfs
|
||||
cd ~/rustfs
|
||||
```
|
||||
|
||||
编辑docker-compose.yml文件
|
||||
|
||||
```shell
|
||||
vim docker-compose.yml
|
||||
```
|
||||
|
||||
新增以下内容
|
||||
|
||||
```yaml
|
||||
services:
|
||||
rustfs:
|
||||
image: 'rustfs/rustfs:latest'
|
||||
container_name: 'rustfs'
|
||||
restart: always
|
||||
environment:
|
||||
- 'TZ:Asia/Shanghai'
|
||||
- 'RUSTFS_ACCESS_KEY=rustfsadmin'
|
||||
- 'RUSTFS_SECRET_KEY=rustfsadmin'
|
||||
- 'RUSTFS_CONSOLE_ENABLE=true'
|
||||
- 'RUSTFS_TLS_PATH=/certs'
|
||||
ports:
|
||||
- '9000:9000'
|
||||
volumes:
|
||||
- /etc/localtime:/etc/localtime:ro
|
||||
- /mnt/rustfs/data:/data
|
||||
- /usr/ssl:/certs
|
||||
command:
|
||||
- "rustfs"
|
||||
- "--console-enable"
|
||||
- "--server-domains"
|
||||
- "rustfs.wenyongdalucky.club"
|
||||
```
|
||||
|
||||
:wq保存后退出
|
||||
|
||||
建立数据挂载目录
|
||||
|
||||
```shell
|
||||
sudo mkdir -p /mnt/rustfs/data
|
||||
```
|
||||
|
||||
在 `~/rustfs` 目录下使用Docker Compose启动容器
|
||||
|
||||
```shell
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
查看日志
|
||||
|
||||
```shell
|
||||
docker logs rustfs -f
|
||||
```
|
||||
|
||||
使用密钥登录的方式,输入账号、密钥
|
||||
|
||||
这里查看之前 docker-compose.yml文件中的 RUSTFS_ACCESS_KEY、RUSTFS_SECRET_KEY 进行登录即可。
|
||||
|
||||
这里就都输入 rustfsadmin登录
|
||||
|
||||
进入到控制台
|
||||
|
||||
创建存储桶 hexo
|
||||
|
||||

|
||||
|
||||
需将桶配置中的访问策略改为 公有,防止无法通过Markdown访问
|
||||
|
||||

|
||||
@@ -133,7 +133,7 @@ error_img:
|
||||
# A simple 404 page
|
||||
error_404:
|
||||
enable: false
|
||||
subtitle: 'Page Not Found'
|
||||
subtitle: "Page Not Found"
|
||||
background: https://i.loli.net/2020/05/19/aKOcLiyPl2JQdFD.png
|
||||
|
||||
post_meta:
|
||||
@@ -551,7 +551,7 @@ canvas_fluttering_ribbon:
|
||||
# https://github.com/hustcc/canvas-nest.js
|
||||
canvas_nest:
|
||||
enable: false
|
||||
color: '0,0,255' #color of lines, default: '0,0,0'; RGB values: (R,G,B).(note: use ',' to separate.)
|
||||
color: "0,0,255" #color of lines, default: '0,0,0'; RGB values: (R,G,B).(note: use ',' to separate.)
|
||||
opacity: 0.7 # the opacity of line (0~1), default: 0.5.
|
||||
zIndex: -1 # z-index property of the background, default: -1.
|
||||
count: 99 # the number of lines, default: 99.
|
||||
@@ -669,7 +669,7 @@ aside:
|
||||
enable: true
|
||||
icon: fab fa-github
|
||||
text: Follow Me
|
||||
link: https://github.com/xxxxxx
|
||||
link: https://github.com/wenyongda
|
||||
card_announcement:
|
||||
enable: true
|
||||
content: This is my Blog
|
||||
@@ -735,9 +735,9 @@ translate:
|
||||
# Time delay
|
||||
translateDelay: 0
|
||||
# The text of the button when the language is Simplified Chinese
|
||||
msgToTraditionalChinese: '繁'
|
||||
msgToTraditionalChinese: "繁"
|
||||
# The text of the button when the language is Traditional Chinese
|
||||
msgToSimplifiedChinese: '簡'
|
||||
msgToSimplifiedChinese: "簡"
|
||||
|
||||
# Read Mode (閲讀模式)
|
||||
readmode: true
|
||||
@@ -823,8 +823,8 @@ aplayerInject:
|
||||
snackbar:
|
||||
enable: false
|
||||
position: bottom-left
|
||||
bg_light: '#49b1f5' # The background color of Toast Notification in light mode
|
||||
bg_dark: '#1f1f1f' # The background color of Toast Notification in dark mode
|
||||
bg_light: "#49b1f5" # The background color of Toast Notification in light mode
|
||||
bg_dark: "#1f1f1f" # The background color of Toast Notification in dark mode
|
||||
|
||||
# https://instant.page/
|
||||
# prefetch (預加載)
|
||||
@@ -894,7 +894,7 @@ CDN:
|
||||
# when set it to local, you need to install hexo-butterfly-extjs
|
||||
third_party_provider: jsdelivr
|
||||
|
||||
# Add version number to CDN, true or false
|
||||
# Add version number to CDN, true or false
|
||||
version: false
|
||||
|
||||
# Custom format
|
||||
@@ -952,4 +952,4 @@ CDN:
|
||||
# prismjs_lineNumber_js:
|
||||
# prismjs_autoloader:
|
||||
# artalk_js:
|
||||
# artalk_css:
|
||||
# artalk_css:
|
||||
|
||||
@@ -40,7 +40,7 @@ search:
|
||||
algolia_search:
|
||||
input_placeholder: Search for Posts
|
||||
hits_empty: "We didn't find any results for the search: ${query}."
|
||||
hits_stats: '${hits} results found in ${time} ms'
|
||||
hits_stats: "${hits} results found in ${time} ms"
|
||||
|
||||
local_search:
|
||||
input_placeholder: Search for Posts
|
||||
@@ -103,6 +103,7 @@ rightside:
|
||||
setting: Setting
|
||||
aside: Toggle between single-column and double-column
|
||||
chat: Chat
|
||||
toggle_sakura: Sakura effect toggled on or off
|
||||
|
||||
copy_copyright:
|
||||
author: Author
|
||||
|
||||
@@ -40,7 +40,7 @@ search:
|
||||
algolia_search:
|
||||
input_placeholder: Search for Posts
|
||||
hits_empty: "We didn't find any results for the search: ${query}."
|
||||
hits_stats: '${hits} results found in ${time} ms'
|
||||
hits_stats: "${hits} results found in ${time} ms"
|
||||
|
||||
local_search:
|
||||
input_placeholder: Search for Posts
|
||||
@@ -103,6 +103,7 @@ rightside:
|
||||
setting: Setting
|
||||
aside: Toggle between single-column and double-column
|
||||
chat: Chat
|
||||
toggle_sakura: Sakura effect toggled
|
||||
|
||||
copy_copyright:
|
||||
author: Author
|
||||
|
||||
@@ -40,12 +40,12 @@ search:
|
||||
load_data: 数据库加载中
|
||||
algolia_search:
|
||||
input_placeholder: 搜索文章
|
||||
hits_empty: '找不到您查询的内容:${query}'
|
||||
hits_stats: '找到 ${hits} 条结果,用时 ${time} 毫秒'
|
||||
hits_empty: "找不到您查询的内容:${query}"
|
||||
hits_stats: "找到 ${hits} 条结果,用时 ${time} 毫秒"
|
||||
|
||||
local_search:
|
||||
input_placeholder: 搜索文章
|
||||
hits_empty: '找不到您查询的内容:${query}'
|
||||
hits_empty: "找不到您查询的内容:${query}"
|
||||
|
||||
pagination:
|
||||
prev: 上一篇
|
||||
@@ -104,6 +104,7 @@ rightside:
|
||||
setting: 设置
|
||||
aside: 单栏和双栏切换
|
||||
chat: 聊天
|
||||
toggle_sakura: 樱花特效切换
|
||||
|
||||
copy_copyright:
|
||||
author: 作者
|
||||
|
||||
@@ -40,12 +40,12 @@ search:
|
||||
load_data: 資料庫載入中
|
||||
algolia_search:
|
||||
input_placeholder: 搜尋文章
|
||||
hits_empty: '找不到您查詢的內容:${query}'
|
||||
hits_stats: '找到 ${hits} 條結果,用時 ${time} 毫秒'
|
||||
hits_empty: "找不到您查詢的內容:${query}"
|
||||
hits_stats: "找到 ${hits} 條結果,用時 ${time} 毫秒"
|
||||
|
||||
local_search:
|
||||
input_placeholder: 搜尋文章
|
||||
hits_empty: '找不到您查詢的內容:${query}'
|
||||
hits_empty: "找不到您查詢的內容:${query}"
|
||||
|
||||
pagination:
|
||||
prev: 上一篇
|
||||
@@ -104,6 +104,7 @@ rightside:
|
||||
setting: 設定
|
||||
aside: 單欄和雙欄切換
|
||||
chat: 聊天
|
||||
toggle_sakura: 櫻花特效切換
|
||||
|
||||
copy_copyright:
|
||||
author: 作者
|
||||
|
||||
@@ -29,14 +29,14 @@ mixin rightsideItem(array)
|
||||
if commentsJsLoad
|
||||
a#to_comment(href="#post-comment" title=_p("rightside.scroll_to_comment"))
|
||||
i.fas.fa-comments
|
||||
when 'xxxx'
|
||||
button#xxxx(type="button" title="测试按钮")
|
||||
i.fas.fa-xxxx
|
||||
when 'sakura'
|
||||
button#toggle_sakura_btn(type="button" title=_p("rightside.toggle_sakura"))
|
||||
i.fas.fa-seedling
|
||||
|
||||
#rightside
|
||||
- const { enable, hide, show } = theme.rightside_item_order
|
||||
- const hideArray = enable ? hide && hide.split(',') : ['readmode','translate','darkmode','hideAside', 'xxxx']
|
||||
- const showArray = enable ? show && show.split(',') : ['toc','chat','comment']
|
||||
- const hideArray = enable ? hide && hide.split(',') : ['readmode','translate','darkmode','hideAside']
|
||||
- const showArray = enable ? show && show.split(',') : ['toc','chat','comment','sakura']
|
||||
|
||||
|
||||
#rightside-config-hide
|
||||
|
||||
@@ -146,7 +146,7 @@ document.addEventListener('DOMContentLoaded', function () {
|
||||
this.classList.toggle('expand-done')
|
||||
}
|
||||
|
||||
function createEle (lang, item, service) {
|
||||
function createEle(lang, item, service) {
|
||||
const fragment = document.createDocumentFragment()
|
||||
|
||||
if (isShowTool) {
|
||||
@@ -205,7 +205,7 @@ document.addEventListener('DOMContentLoaded', function () {
|
||||
/**
|
||||
* PhotoFigcaption
|
||||
*/
|
||||
function addPhotoFigcaption () {
|
||||
function addPhotoFigcaption() {
|
||||
document.querySelectorAll('#article-container img').forEach(function (item) {
|
||||
const parentEle = item.parentNode
|
||||
const altValue = item.title || item.alt
|
||||
@@ -265,7 +265,7 @@ document.addEventListener('DOMContentLoaded', function () {
|
||||
}
|
||||
|
||||
// find the scroll direction
|
||||
function scrollDirection (currentTop) {
|
||||
function scrollDirection(currentTop) {
|
||||
const result = currentTop > initTop // true is down & false is up
|
||||
initTop = currentTop
|
||||
return result
|
||||
@@ -278,38 +278,38 @@ document.addEventListener('DOMContentLoaded', function () {
|
||||
const isChatBtnShow = typeof chatBtnShow === 'function'
|
||||
|
||||
const scrollTask = btf.throttle(() => {
|
||||
const currentTop = window.scrollY || document.documentElement.scrollTop
|
||||
const isDown = scrollDirection(currentTop)
|
||||
if (currentTop > 56) {
|
||||
if (isDown) {
|
||||
if ($header.classList.contains('nav-visible')) $header.classList.remove('nav-visible')
|
||||
if (isChatBtnShow && isChatShow === true) {
|
||||
chatBtnHide()
|
||||
isChatShow = false
|
||||
}
|
||||
} else {
|
||||
if (!$header.classList.contains('nav-visible')) $header.classList.add('nav-visible')
|
||||
if (isChatBtnHide && isChatShow === false) {
|
||||
chatBtnShow()
|
||||
isChatShow = true
|
||||
}
|
||||
}
|
||||
$header.classList.add('nav-fixed')
|
||||
if (window.getComputedStyle($rightside).getPropertyValue('opacity') === '0') {
|
||||
$rightside.style.cssText = 'opacity: 0.8; transform: translateX(-58px)'
|
||||
const currentTop = window.scrollY || document.documentElement.scrollTop
|
||||
const isDown = scrollDirection(currentTop)
|
||||
if (currentTop > 56) {
|
||||
if (isDown) {
|
||||
if ($header.classList.contains('nav-visible')) $header.classList.remove('nav-visible')
|
||||
if (isChatBtnShow && isChatShow === true) {
|
||||
chatBtnHide()
|
||||
isChatShow = false
|
||||
}
|
||||
} else {
|
||||
if (currentTop === 0) {
|
||||
$header.classList.remove('nav-fixed', 'nav-visible')
|
||||
if (!$header.classList.contains('nav-visible')) $header.classList.add('nav-visible')
|
||||
if (isChatBtnHide && isChatShow === false) {
|
||||
chatBtnShow()
|
||||
isChatShow = true
|
||||
}
|
||||
$rightside.style.cssText = "opacity: ''; transform: ''"
|
||||
}
|
||||
|
||||
if (document.body.scrollHeight <= innerHeight) {
|
||||
$header.classList.add('nav-fixed')
|
||||
if (window.getComputedStyle($rightside).getPropertyValue('opacity') === '0') {
|
||||
$rightside.style.cssText = 'opacity: 0.8; transform: translateX(-58px)'
|
||||
}
|
||||
}, 200)
|
||||
|
||||
} else {
|
||||
if (currentTop === 0) {
|
||||
$header.classList.remove('nav-fixed', 'nav-visible')
|
||||
}
|
||||
$rightside.style.cssText = "opacity: ''; transform: ''"
|
||||
}
|
||||
|
||||
if (document.body.scrollHeight <= innerHeight) {
|
||||
$rightside.style.cssText = 'opacity: 0.8; transform: translateX(-58px)'
|
||||
}
|
||||
}, 200)
|
||||
|
||||
window.scrollCollect = scrollTask
|
||||
|
||||
window.addEventListener('scroll', scrollCollect)
|
||||
@@ -455,7 +455,7 @@ document.addEventListener('DOMContentLoaded', function () {
|
||||
newEle.className = 'fas fa-sign-out-alt exit-readmode'
|
||||
$body.appendChild(newEle)
|
||||
|
||||
function clickFn () {
|
||||
function clickFn() {
|
||||
$body.classList.remove('read-mode')
|
||||
newEle.remove()
|
||||
newEle.removeEventListener('click', clickFn)
|
||||
@@ -501,6 +501,17 @@ document.addEventListener('DOMContentLoaded', function () {
|
||||
: saveToLocal.set('aside-status', 'hide', 2)
|
||||
$htmlDom.toggle('hide-aside')
|
||||
},
|
||||
toggleSakuraBtn: () => {
|
||||
const toggleBtn = document.getElementById('toggle_sakura_btn');
|
||||
if (toggleBtn) {
|
||||
// toggleBtn.addEventListener('click', function () {
|
||||
const sakuraEffect = document.getElementById('canvas_sakura');
|
||||
if (sakuraEffect) {
|
||||
sakuraEffect.style.display = (sakuraEffect.style.display === 'none' || sakuraEffect.style.display === '') ? 'block' : 'none';
|
||||
}
|
||||
// });
|
||||
}
|
||||
},
|
||||
|
||||
runMobileToc: () => {
|
||||
if (window.getComputedStyle(document.getElementById('card-toc')).getPropertyValue('opacity') === '0') window.mobileToc.open()
|
||||
@@ -529,6 +540,9 @@ document.addEventListener('DOMContentLoaded', function () {
|
||||
case 'hide-aside-btn':
|
||||
rightSideFn.hideAsideBtn()
|
||||
break
|
||||
case 'toggle_sakura_btn':
|
||||
rightSideFn.toggleSakuraBtn()
|
||||
break
|
||||
default:
|
||||
break
|
||||
}
|
||||
@@ -556,10 +570,10 @@ document.addEventListener('DOMContentLoaded', function () {
|
||||
let textFont; const copyFont = window.getSelection(0).toString()
|
||||
if (copyFont.length > copyright.limitCount) {
|
||||
textFont = copyFont + '\n' + '\n' + '\n' +
|
||||
copyright.languages.author + '\n' +
|
||||
copyright.languages.link + window.location.href + '\n' +
|
||||
copyright.languages.source + '\n' +
|
||||
copyright.languages.info
|
||||
copyright.languages.author + '\n' +
|
||||
copyright.languages.link + window.location.href + '\n' +
|
||||
copyright.languages.source + '\n' +
|
||||
copyright.languages.info
|
||||
} else {
|
||||
textFont = copyFont
|
||||
}
|
||||
|
||||