network

设置网关导致端口网关失效

参考这里

1
2
3
ip route add 192.168.6.0/24 dev br0 table 16
ip route add default via 192.168.6.1 dev br0 table 16
ip rule iif to ipproto tcp sport 10014 lookup 16

另外一种方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
ip route add 192.168.6.0/24 dev br0 table 10
ip route add default via 192.168.6.1 table 10
ip route add 192.168.9.0/24 dev br1 table 12
ip route add default via 192.168.9.1 table 12
ip rule add from 192.168.6.0/24 table 10 priority 1
ip rule add from 192.168.9.0/24 table 12 priority 2

# 添加 docker 网络
ip route add 172.17.0.0/16 dev docker0 table 10
ip route add 172.17.0.0/16 dev docker0 table 12

# 刷新配置
ip route flush cache

# 校验
$ ip route show table 12
default via 192.168.9.1 dev br1
172.17.0.0/16 dev docker0 scope link
192.168.9.0/24 dev br1 scope link

示例

1
2
3
4
5
6
7
8
9
10
11
12
13
# out
ip route add default via 192.168.6.1 dev ens8 table 10
ip route add default via 192.168.9.1 dev ens9 table 12
# in
ip rule add from 192.168.6.0/24 table 10 priority 1
ip rule add from 192.168.9.0/24 table 12 priority 2 # 可以不设置 priority

# 如果有设置了默认的路由,可以忽略其中的一个,比如有如下默认路由
ip route add default via 192.168.6.1 dev ens8
# 那么只需要设置 192.168.9.0/24
# ip route add default via 192.168.9.1 dev ens9 table 12
ip route add 192.168.9.0/24 dev ens9 proto kernel scope link src 192.168.9.8
ip rule add from 192.168.9.0/24 table 12

连接路由器的 VPN 之后无法访问内网服务

原因

路由器局域网网段和外网网段冲突,导致访问局域网 ip 不走 vpn 网络。

设置

1
2
3
4
5
6
7
# macos, route 命令
## 查看路由表
sudo netstat -rn
192.168.6.6 link#6 UHRLWIi en0 8
## en0 是 wifi 网络接口, vpn 的网络端口是 utun3
## 修改路由, 把 192.168.6.0/24 所有网段的路由走 vpn
sudo route change 192.168.6.0/24 -interface utun3

USB 外接网卡

1
2
3
4
5
6
7
8
9
10
$ lshw -c network
WARNING: you should run this program as super-user.
*-network
...
logical name: enp0s31f6
...
*-network DISABLED
...
logical name: enxf8e43b1a1229
...

samba server

安装

1
2
3
# ubuntu
sudo apt update
sudo apt install samba

配置

1
2
3
4
5
6
7
sudo vim /etc/samba/smb.conf
# 在文档最后添加
[sambashare]
comment = Samba on Ubuntu
path = /home/username/sambashare
read only = no
browsable = yes

重启服务

1
sudo service smbd restart

添加用户并设置密码

1
sudo smbpasswd -a <username>

HTTPS 证书

CertBot

使用 CertBot 进行证书签发及自动更新。

1
2
3
4
5
6
7
8
9
10
# 安装 certbot
$ sudo snap install --classic certbot
$ sudo ln -s /snap/bin/certbot /usr/bin/certbot

# 证书签发
# 需要: 关闭监听 80 端口的 web server
$ sudo certbot certonly --standalone
# 依次输入 邮箱、域名等
# 证书会放在 /etc/letsencrypt/live/{domain}/ 下
# CertBot 会创建定时任务刷新证书

Caddy

Caddy Server 可以自动识别证书,无需指定证书位置。

1
2
3
exploring.fun {
reverse_proxy http://172.60.2.1:30800
}

microk8s usage

描述

参考 官方文档,搭建一个三节点 k8s 集群。

节点 ip
k8s01-1 10.1.0.78
k8s01-2 10.1.0.62
k8s01-3 10.1.0.242

alias

1
2
3
4
5
6
7
# ~/.bash_aliases
alias k='microk8s kubectl'
alias mk='microk8s'

# 或者 ~/.local/bin/kubectl, 适配 k9s
#!/bin/bash
exec microk8s.kubectl $(echo "$*" | sed 's/-- sh.*/sh/')

加入用户组

1
2
3
4
sudo usermod -a -G microk8s $USER
sudo chown -f -R $USER ~/.kube
# 重新进入 session
su - $USER

Hosts

所有节点

1
2
3
10.1.0.78 k8s01-1
10.1.0.62 k8s01-2
10.1.0.242 k8s01-3

初始化集群

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# k8s01-1 主节点
$ mk add-node
From the node you wish to join to this cluster, run the following:
microk8s join 192.168.9.103:25000/5b502d061dd31ec58d1f6ddf96e10c56/be841c6899a7

Use the '--worker' flag to join a node as a worker not running the control plane, eg:
microk8s join 10.1.0.78:25000/5b502d061dd31ec58d1f6ddf96e10c56/be841c6899a7 --worker

If the node you are adding is not reachable through the default interface you can use one of the following:
microk8s join 10.1.0.78:25000/5b502d061dd31ec58d1f6ddf96e10c56/be841c6899a7

# k8s01-2 worker 节点
microk8s join 10.1.0.78:25000/5b502d061dd31ec58d1f6ddf96e10c56/be841c6899a7 --worker

# 对 k8s01-3, 重复上述操作

查看状态

1
2
3
4
5
$ k get nodes
NAME STATUS ROLES AGE VERSION
k8s01-1 Ready <none> 2d12h v1.24.3-2+63243a96d1c393
k8s01-2 Ready <none> 77s v1.24.3-2+63243a96d1c393
k8s01-3 Ready <none> 64s v1.24.3-2+63243a96d1c393

更详细的状态

1
2
3
4
5
$ k get node -o wide
NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME
k8s01-1 Ready <none> 2d12h v1.24.3-2+63243a96d1c393 10.1.0.78 <none> Ubuntu 20.04.4 LTS 5.4.0-124-generic containerd://1.5.13
k8s01-2 Ready <none> 5m23s v1.24.3-2+63243a96d1c393 10.1.0.62 <none> Ubuntu 20.04.4 LTS 5.4.0-124-generic containerd://1.5.13
k8s01-3 Ready <none> 5m10s v1.24.3-2+63243a96d1c393 10.1.0.242 <none> Ubuntu 20.04.4 LTS 5.4.0-124-generic containerd://1.5.13

安装插件

1
2
# 主节点
mk enable dns storage dashboard helm3

获取 k8s 配置

1
2
mkdir ~/.kube
mk config > ~/.kube/config

问题排查

查看事件

1
k get events --sort-by=.metadata.creationTimestamp --namespace=kube-system

异常

Failed create pod sandbox

错误信息

1
Failed create pod sandbox: rpc error: code = Unknown desc = failed to set up sandbox container ... error getting ClusterInformation: Get ... https://10.152.183.1:443 ...

原因

1
2
NAMESPACE↑                 NAME                      TYPE                     CLUSTER-IP     
default kubernetes ClusterIP 10.152.183.1

错误信息提示请求 ClusterIP 异常,检查节点 IP。

1
2
3
4
$ k get nodes -o wide
NAME STATUS ROLES AGE VERSION INTERNAL-IP ... KERNEL-VERSION CONTAINER-RUNTIME
a Ready <none> 16h v1.27.2 172.21.0.3 ... 5.4.0-126-generic containerd://1.6.15
b Ready <none> 16h v1.27.2 192.168.6.201 ... 5.15.0-76-generic containerd://1.6.15

解决
在 b 节点无法通过 a 的 INTERNAL-IP 访问 a(controller) 节点,修改两个节点的 --node-ip 为可以访问的 ip。

1
2
3
4
5
6
7
8
9
10
11
microk8s stop
# or for workers: sudo snap stop microk8s

sudo vim.tiny /var/snap/microk8s/current/args/kubelet
# Add this to bottom: --node-ip=<this-specific-node-lan-ip>

sudo vim.tiny /var/snap/microk8s/current/args/kube-apiserver
# Add this to bottom: --advertise-address=<this-specific-node-lan-ip>

microk8s start
# or for workers: sudo snap start microk8s

certificate is valid for kubernetes … not for mydomain.com

参考 这里

1
2
3
4
5
6
7
8
9
10
11
12
$ vim /var/snap/microk8s/current/certs/csr.conf.template
# 添加域名
[ alt_names ]
DNS.1 = kubernetes
DNS.2 = kubernetes.default
DNS.3 = kubernetes.default.svc
DNS.4 = kubernetes.default.svc.cluster
DNS.5 = kubernetes.default.svc.cluster.local
DNS.6 = mydomain.com # 添加一行

# 生效
$ sudo microk8s refresh-certs --cert server.crt

microk8s 安装

文档

安装

1
sudo snap install microk8s --classic 

加入用户组

1
2
3
4
sudo usermod -a -G microk8s $USER
sudo chown -f -R $USER ~/.kube
# 重新进入 session
su - $USER

配置 k8s.gcr.io 镜像地址

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# create a directory with the registry name
sudo mkdir -p /var/snap/microk8s/current/args/certs.d/k8s.gcr.io

# create the hosts.toml file pointing to the mirror
echo '
server = "https://k8s.gcr.io"

[host."https://registry.aliyuncs.com/v2/google_containers"]
capabilities = ["pull", "resolve"]
override_path = true
' | sudo tee -a /var/snap/microk8s/current/args/certs.d/k8s.gcr.io/hosts.toml


# 2
sudo mkdir -p /var/snap/microk8s/current/args/certs.d/registry.k8s.io
echo '
server = "registry.k8s.io"

[host."https://registry.aliyuncs.com/v2/google_containers"]
capabilities = ["pull", "resolve"]
override_path = true
' | sudo tee -a /var/snap/microk8s/current/args/certs.d/registry.k8s.io/hosts.toml

需要重启

1
sudo snap restart microk8s

检查状态

1
2
# 如果不翻墙/替换镜像, 会在这里卡住
microk8s status --wait-ready

配置

配置 kubectl 命令

1
2
3
4
5
mkdir -p ~/.local/bin/
vim ~/.local/bin/kubectl
# 输入如下内容
#!/bin/bash
exec /snap/bin/microk8s.kubectl $(echo "$*" | sed 's/-- sh.*/sh/')

配置别名

1
2
3
4
5
# vim ~/.bash_aliases
alias kubectl='microk8s kubectl'
alias k='microk8s kubectl'
alias mk='microk8s'
alias helm='microk8s helm3'

设置私有镜像仓库

1
2
3
4
5
$ docker login ... # 登录私有镜像仓库
$ kubectl create secret generic regcred \
--from-file=.dockerconfigjson=$HOME/.docker/config.json \
--type=kubernetes.io/dockerconfigjson \
--namespace=default

组建集群

安装 dashboard

1
2
3
microk8s enable dns dashboard
# 生成 token
microk8s kubectl create token -n kube-system default --duration=8544h

k8s.gcr.io 无法拉取镜像

配置 k8s.gcr.io 理论上可以解决问题。

1
2
3
4
5
6
7
8
9
10
11
# pause
## 从阿里云镜像拉取
docker pull registry.aliyuncs.com/google_containers/pause:3.7
## 重命名
docker tag registry.aliyuncs.com/google_containers/pause:3.7 k8s.gcr.io/pause:3.7
docker tag registry.aliyuncs.com/google_containers/pause:3.7 registry.k8s.io/pause:3.7

# metric server
docker pull registry.aliyuncs.com/google_containers/metrics-server:v0.5.2
docker tag registry.aliyuncs.com/google_containers/metrics-server:v0.5.2 k8s.gcr.io/metrics-server/metrics-server:v0.5.2
docker tag registry.aliyuncs.com/google_containers/metrics-server:v0.5.2 registry.k8s.io/metrics-server/metrics-server:v0.5.2

Join 集群

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# master 节点运行
$ microk8s add-node
From the node you wish to join to this cluster, run the following:
microk8s join 192.168.1.230:25000/92b2db237428470dc4fcfc4ebbd9dc81/2c0cb3284b05

Use the '--worker' flag to join a node as a worker not running the control plane, eg:
microk8s join 192.168.1.230:25000/92b2db237428470dc4fcfc4ebbd9dc81/2c0cb3284b05 --worker

If the node you are adding is not reachable through the default interface you can use one of the following:
microk8s join 192.168.1.230:25000/92b2db237428470dc4fcfc4ebbd9dc81/2c0cb3284b05
microk8s join 10.23.209.1:25000/92b2db237428470dc4fcfc4ebbd9dc81/2c0cb3284b05
microk8s join 172.17.0.1:25000/92b2db237428470dc4fcfc4ebbd9dc81/2c0cb3284b05

# slave 节点运行
$ microk8s join 172.17.0.1:25000/92b2db237428470dc4fcfc4ebbd9dc81/2c0cb3284b05

k8s 配置

k8s objects

官方文档。k8s objects 是 k8s 系统中的持久化实体,用来表示服务集群的状态。

Spec 和 Status

每个 k8s object 包含两个字段,spec 和 status。spec 是事先设置的期望的状态,由使用者指定。status 用来描述当前的状态,由 k8s 系统维护。

描述 k8s objects

当在 k8s 系统中创建 object 时,需要指定 object spec,来描述期望的状态,以及基础信息。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
apiVersion: apps/v1
kind: Deployment
metadata:
# 部署的名字
name: nginx-deployment
spec:
# 用于选择要管理的Pod对象,该选择器匹配与Deployment相关联的Pod, 所有标签都匹配才行
selector:
matchLabels:
app: nginx
replicas: 2 # tells deployment to run 2 pods matching the template
# 定义 pod 相关信息
template:
metadata:
labels:
app: nginx
spec:
# 定义容器,可以多个
containers:
- name: nginx
image: nginx:1.14.2
ports:
- containerPort: 80
env:
- name: ENV_NAME
value: ENV_VALUE
# 按标签选择机器
nodeSelector:
<label-name>: <label-value>
# 设置机器亲和性
affinity:
# 设置 node 亲和性
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: <label-name>
operator: In
values:
- <label-value>
# 设置 pod 亲和性
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: app.kubernetes.io/name
operator: In
values:
- <pod-name>
- <pod-name>
topologyKey: kubernetes.io/hostname

需要的字段

  • apiVersion - 创建 k8s object 时使用的 API 版本
  • kind - 创建的 object 的类型
  • metadata - 用来唯一标识 object,包括 nameUIDnamespace
  • spec - k8s object 期望的状态

服务

端口

  • ClusterIP,集群内可以访问,也可以使用 port-forward (用于测试)的方式访问
  • NodePort,直接通过节点访问(k8s 节点,master & work)
    • 需要定义 nodePort
    • 不同的流量会被转发到不同的 pod
  • LoadBalancer,负载均衡方式访问(需要负载均衡器)

ant design

Upload 集成在菜单/下拉框选项

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
let items = [            
{
label: <Upload
multiple={false}
showUploadList={false}
accept=".json"
customRequest={onSelect}>导入</Upload>,
icon: <ImportOutlined/>,
key: 1
}
]

<Menu
selectedKeys={1}
items={menuItems}
/>

// 自定义上传逻辑
const onSelect = (info: any) => {
let {file} = info
let reader = new FileReader();
reader.onload = (e: ProgressEvent<FileReader>) => {
if (e && e.target && e.target.result) {
let space: string = e.target.result.toString();
importSpace(JSON.parse(space)) // importSpace: 发送请求, 返回 Promise 对象
.then(() => {
message.success("导入成功");
})
.catch(e => message.error("导入失败"));
}
};
reader.readAsText(file);
};

TroubleShooting

V4 升 V5

组件兼容

1
2
3
yarn add @ant-design/compatible@v5-compatible-v4

import { Comment } from '@ant-design/compatible';

Babel 配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
{
"presets": [
...
],
"plugins": [
...
[
"import",
{
"libraryName": "antd",
"libraryDirectory": "es",
"style": true
}
]
]
}

css

1. Flexbox 布局(推荐首选)

1
2
3
4
5
.parent {
display: flex;
justify-content: center; /* 水平居中 */
align-items: center; /* 垂直居中 */
}
  • 特点:无需计算子元素尺寸,支持动态内容,代码简洁,兼容现代浏览器(IE10+)。
  • 适用场景:响应式布局、简单居中和复杂布局混合场景。

2. 绝对定位 + Transform

1
2
3
4
5
6
7
8
9
.parent {
position: relative; /* 父元素需设置定位 */
}
.child {
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%); /* 自动计算偏移量 */
}
  • 特点:不依赖子元素尺寸,兼容性较好(IE9+)。
  • 适用场景:固定尺寸父容器、需要精准控制的定位场景。

3. 绝对定位 + Margin Auto

1
2
3
4
5
6
7
8
9
10
11
.parent {
position: relative;
}
.child {
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
margin: auto;
}
  • 特点:需子元素固定宽高,兼容性极佳(IE7+)。
  • 适用场景:已知子元素尺寸的传统项目或需要兼容旧浏览器。

4. Grid 布局(现代方案)

1
2
3
4
.parent {
display: grid;
place-items: center; /* 同时水平和垂直居中 */
}
  • 特点:代码最简洁,支持复杂布局,但兼容性略差(IE 不支持)。
  • 适用场景:现代浏览器项目、需要网格布局的场景。

5. 表格布局

1
2
3
4
5
6
7
8
.parent {
display: table-cell;
vertical-align: middle; /* 垂直居中 */
text-align: center; /* 水平居中 */
}
.child {
display: inline-block; /* 行内块元素 */
}
  • 特点:兼容性好(IE8+),但语义化较差。
  • 适用场景:需要兼容旧版浏览器且不固定宽高的内容。

6. 传统负 Margin 法

1
2
3
4
5
6
7
8
9
10
.parent {
position: relative;
}
.child {
position: absolute;
left: 50%;
top: 50%;
margin-left: -50px; /* 子元素宽度一半 */
margin-top: -50px; /* 子元素高度一半 */
}
  • 特点:需明确子元素尺寸,兼容性极佳(IE6+)。
  • 适用场景:传统项目且子元素尺寸固定。

总结选择建议

方法 是否需要子元素尺寸 兼容性 适用优先级
Flexbox IE10+ ★★★★★
绝对定位 + Transform IE9+ ★★★★☆
Grid 布局 现代浏览器 ★★★★☆
绝对定位 + Margin Auto IE7+ ★★★☆☆
表格布局 IE8+ ★★☆☆☆
负 Margin IE6+ ★★☆☆☆

关键注意事项

  1. 父元素尺寸:若使用百分比(如height: 100%),需确保父元素的父级有明确高度(如html, body { height: 100% })
  2. 盒模型干扰:若子元素有 padding 或 border ,建议设置 box-sizing: border-box 防止溢出
  3. 浏览器前缀:老旧项目可能需要为 transform 或 flex 添加 -webkit- 等前缀
  4. 推荐优先使用 FlexboxGrid 布局,其次是 绝对定位 + Transform,其他方法可作为备选方案。