Skip to main content

docker buildx构建多平台镜像

· 6 min read
1cobot
开发者

安装docker环境

环境准备

准备2台机器,分别是amd和arm架构

主机IP架构docker版本buildx版本buildkit镜像版本
build-amd192.168.91.47amd6425.0.4v0.13.0latest
build-arm192.168.91.48arm6425.0.4v0.13.0latest

安装环境

build-amd

# step 1: 安装必要的一些系统工具
sudo apt-get update
sudo apt-get -y install apt-transport-https ca-certificates curl software-properties-common
# step 2: 安装GPG证书
curl -fsSL https://mirrors.aliyun.com/docker-ce/linux/ubuntu/gpg | sudo apt-key add -
# Step 3: 写入软件源信息
sudo add-apt-repository "deb [arch=amd64] https://mirrors.aliyun.com/docker-ce/linux/ubuntu $(lsb_release -cs) stable"
# Step 4: 更新并安装Docker-CE
sudo apt-get -y update
sudo apt-get -y install docker-ce

# 安装指定版本的Docker-CE:
# Step 1: 查找Docker-CE的版本:
# apt-cache madison docker-ce
# docker-ce | 17.03.1~ce-0~ubuntu-xenial | https://mirrors.aliyun.com/docker-ce/linux/ubuntu xenial/stable amd64 Packages
# docker-ce | 17.03.0~ce-0~ubuntu-xenial | https://mirrors.aliyun.com/docker-ce/linux/ubuntu xenial/stable amd64 Packages
# Step 2: 安装指定版本的Docker-CE: (VERSION例如上面的17.03.1~ce-0~ubuntu-xenial)
# sudo apt-get -y install docker-ce=[VERSION]

版本验证

# docker 版本
root@build-amd:~# docker version
Client: Docker Engine - Community
Version: 25.0.4
API version: 1.44
Go version: go1.21.8
Git commit: 1a576c5
Built: Wed Mar 6 16:32:14 2024
OS/Arch: linux/amd64
Context: default

Server: Docker Engine - Community
Engine:
Version: 25.0.4
API version: 1.44 (minimum version 1.24)
Go version: go1.21.8
Git commit: 061aa95
Built: Wed Mar 6 16:32:14 2024
OS/Arch: linux/amd64
Experimental: false
containerd:
Version: 1.6.28
GitCommit: ae07eda36dd25f8a1b98dfbf587313b99c0190bb
runc:
Version: 1.1.12
GitCommit: v1.1.12-0-g51d5e94
docker-init:
Version: 0.19.0
GitCommit: de40ad0

# docker buildx 版本
root@build-amd:~# docker buildx version
github.com/docker/buildx v0.13.0 0de5f1c

build-arm
arm架构优先使用二进制安装

# 下载docker离线安装包
root@build-arm:~# wget https://download.docker.com/linux/static/stable/aarch64/docker-25.0.4.tgz

# 下载buildx离线包
root@build-arm:~# wget https://github.com/docker/buildx/releases/download/v0.13.0/buildx-v0.13.0.linux-arm64

# 解压缩
root@build-arm:~# tar xvf docker-25.0.4.tgz

# 安装前准备
root@build-arm:~# cd docker/

root@build-arm:~/docker# ls
containerd containerd-shim-runc-v2 ctr docker dockerd docker-init docker-proxy runc
# bin目录存放可执行文件,plugin目录存放buildx插件,systemd目录存放systemd管理文件
root@build-arm:~/docker# mkdir {bin,plugin,systemd}

# 移动可执行文件至bin目录
root@build-arm:~/docker# mv containerd containerd-shim-runc-v2 ctr docker dockerd docker-init docker-proxy runc bin/
root@build-arm:~/docker# ls bin/
containerd containerd-shim-runc-v2 ctr docker dockerd docker-init docker-proxy runc

# 移动buildx至plugin目录
root@build-arm:~# mv buildx-v0.13.0.linux-arm64 docker/plugin/docker-buildx
root@build-arm:~# chmod +x docker/plugin/docker-buildx
root@build-arm:~# ls docker/plugin/docker-buildx
docker/plugin/docker-buildx

# systemd
root@build-arm:~# cd docker/systemd/
root@build-arm:~/docker/systemd# ls
containerd.service docker.service docker.socket

# 查看目录层级
root@build-arm:~# tree docker
docker
├── bin
│   ├── containerd
│   ├── containerd-shim-runc-v2
│   ├── ctr
│   ├── docker
│   ├── dockerd
│   ├── docker-init
│   ├── docker-proxy
│   └── runc
├── plugin
│   └── docker-buildx
└── systemd
├── containerd.service
├── docker.service
└── docker.socket

3 directories, 12 files

执行安装脚本

#!/bin/bash

# 创建用户组
groupadd docker

# 创建buildx插件目录
mkdir -p /usr/local/lib/docker/cli-plugins

# 授权
chmod +x bin/* plugin/*

# 复制可执行文件至PATH路径
cp bin/* /usr/bin/

# 复制插件至插件目录
cp plugin/* /usr/local/lib/docker/cli-plugins

# 复制systemd文件到系统system目录下
cp systemd/* /etc/systemd/system/

# 重新加载生效
systemctl daemon-reload

# 开机自启动
systemctl enable containerd

# 服务启动
systemctl enable docker

# 开机自启动
systemctl start containerd

# 服务启动
systemctl start docker
buildx插件介绍

默认地址:
Linux:

  • $HOME/.docker/cli-plugins
  • /usr/local/lib/docker/cli-plugins
  • /usr/local/libexec/docker/cli-plugins
  • /usr/lib/docker/cli-plugins
  • /usr/libexec/docker/cli-plugins

版本验证

# docker 版本
root@build-arm:~# docker version
Client: Docker Engine - Community
Version: 25.0.4
API version: 1.44
Go version: go1.21.8
Git commit: 1a576c5
Built: Wed Mar 6 16:32:14 2024
OS/Arch: linux/arm64
Context: default

Server: Docker Engine - Community
Engine:
Version: 25.0.4
API version: 1.44 (minimum version 1.24)
Go version: go1.21.8
Git commit: 061aa95
Built: Wed Mar 6 16:32:14 2024
OS/Arch: linux/arm64
Experimental: false
containerd:
Version: 1.6.28
GitCommit: ae07eda36dd25f8a1b98dfbf587313b99c0190bb
runc:
Version: 1.1.12
GitCommit: v1.1.12-0-g51d5e94
docker-init:
Version: 0.19.0
GitCommit: de40ad0

# docker buildx 版本
root@build-arm:~# docker buildx version
github.com/docker/buildx v0.13.0 0de5f1c

配置 Remote driver

生成证书

证书生成amd机器上生成

root@build-amd:~# SAN="127.0.0.1"
root@build-amd:~# docker buildx bake https://github.com/moby/buildkit.git#master:examples/create-certs

# 创建证书目录
root@build-amd:~# mkdir -p /etc/buildkit/certs
root@build-amd:~# cp -r .certs/* /etc/buildkit/certs

复制证书到build-arm机器

# 设置变量值
root@build-amd:~# arm_ip=192.168.91.48
root@build-amd:~# arm_user=root

# 远程登录创建证书目录
root@build-amd:~# ssh $arm_user@$arm_ip mkdir -p /etc/buildkit

# 复制证书
root@build-amd:~# scp -r /etc/buildkit/certs $arm_user@$arm_ip:/etc/buildkit/certs

配置builkit

root@build-amd:~# vim /etc/buildkitd.toml

[registry."dockerhub.example.com"]
mirrors = ["192.168.91.49"]
http = true
insecure = true

运行容器

执行如下命令运行buildkitd容器

buildx-amd和build-arm机器均需操作

docker run -d \
--restart=always \
--name=remote-buildkitd \
--privileged \
-p 1234:1234 \
-v /etc/buildkit/:/etc/buildkit/ \
moby/buildkit \
--addr tcp://0.0.0.0:1234 \
--tlscacert /etc/buildkit/certs/daemon/ca.pem \
--tlscert /etc/buildkit/certs/daemon/cert.pem \
--tlskey /etc/buildkit/certs/daemon/key.pem

注册Remote driver

在build-amd的runner上运行

root@build-amd:~# arm_ip=192.168.91.48
root@build-amd:~# SAN="127.0.0.1"

root@build-amd:~# docker buildx create --name remote-container --node remote-container0 --driver remote --driver-opt cacert=/etc/buildkit/certs/client/ca.pem,cert=/etc/buildkit/certs/client/cert.pem,key=/etc/buildkit/certs/client/key.pem,servername=$SAN tcp://127.0.0.1:1234

root@build-amd:~# docker buildx create --append --name remote-container --node remote-container1 --driver remote --driver-opt cacert=/etc/buildkit/certs/client/ca.pem,cert=/etc/buildkit/certs/client/cert.pem,key=/etc/buildkit/certs/client/key.pem,servername=$SAN tcp://$arm_ip:1234


# 配置docker buildx 使用remote-containerd
root@build-amd:~# docker buildx use remote-container

systemd管理文件

::: details containerd.service [Unit] Description=containerd container runtime
Documentation=https://containerd.io
After=network.target local-fs.target

[Service]
ExecStartPre=-/sbin/modprobe overlay
ExecStart=/usr/bin/containerd

Type=notify
Delegate=yes
KillMode=process
Restart=always
RestartSec=5
LimitNPROC=infinity
LimitCORE=infinity
LimitNOFILE=infinity
TasksMax=infinity
OOMScoreAdjust=-999

[Install]
WantedBy=multi-user.target ::: ::: details docker.service [Unit]
Description=Docker Application Container Engine
Documentation=https://docs.docker.com
After=network-online.target docker.socket firewalld.service containerd.service time-set.target
Wants=network-online.target containerd.service
Requires=docker.socket

[Service]
Type=notify
ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock
ExecReload=/bin/kill -s HUP $MAINPID
TimeoutStartSec=0
RestartSec=2
Restart=always

StartLimitBurst=3

StartLimitInterval=60s

LimitNPROC=infinity
LimitCORE=infinity

TasksMax=infinity

Delegate=yes

KillMode=process
OOMScoreAdjust=-500

[Install]
WantedBy=multi-user.target
:::

::: details docker.socket [Unit]
Description=Docker Socket for the API

[Socket]
ListenStream=/run/docker.sock
SocketMode=0660
SocketUser=root
SocketGroup=docker

[Install]
WantedBy=sockets.target
:::

下载地址

gitlab集成钉钉扫码登录

· 3 min read
1cobot
开发者

安装gitlab-ce

# 01 更新软件源
root@ecs-e58f:~# apt update

# 02 下载gitlab-ce安装包
root@ecs-e58f:~# wget https://mirrors.tuna.tsinghua.edu.cn/gitlab-ce/ubuntu/pool/focal/main/g/gitlab-ce/gitlab-ce_14.6.3-ce.0_amd64.deb

# 03 安装gitlab
root@ecs-e58f:~# dpkg -i gitlab-ce_14.6.3-ce.0_amd64.deb

# 04 编译配置文件
root@ecs-e58f:~# vim /etc/gitlab/gitlab.rb

# 如下修改 external_url 为本机地址或者域名
root@ecs-e58f:~# grep external_url /etc/gitlab/gitlab.rb
##! For more details on configuring external_url see:
external_url 'http://1.94.109.197'

# 05 重新加载配置文件
root@ecs-e58f:~# gitlab-ctl reconfigure

# 06 启动gitlab
root@ecs-e58f:~# gitlab-ctl start
ok: run: alertmanager: (pid 164302) 523s
ok: run: gitaly: (pid 164290) 523s
ok: run: gitlab-exporter: (pid 164263) 525s
ok: run: gitlab-workhorse: (pid 164243) 526s
ok: run: grafana: (pid 164395) 522s
ok: run: logrotate: (pid 163289) 663s
ok: run: nginx: (pid 163794) 599s
ok: run: node-exporter: (pid 164257) 526s
ok: run: postgres-exporter: (pid 164310) 523s
ok: run: postgresql: (pid 163521) 644s
ok: run: prometheus: (pid 164272) 524s
ok: run: puma: (pid 163711) 613s
ok: run: redis: (pid 163328) 657s
ok: run: redis-exporter: (pid 164265) 525s
ok: run: sidekiq: (pid 163734) 607s

访问gitlab

浏览器访问

# 浏览器访问
http://1.94.107.197

初始密码登录

root@ecs-e58f:~# cat /etc/gitlab/initial_root_password 
# WARNING: This value is valid only in the following conditions
# 1. If provided manually (either via `GITLAB_ROOT_PASSWORD` environment variable or via `gitlab_rails['initial_root_password']` setting in `gitlab.rb`, it was provided before database was seeded for the first time (usually, the first reconfigure run).
# 2. Password hasn't been changed manually, either via UI or via command line.
#
# If the password shown here doesn't work, you must reset the admin password following https://docs.gitlab.com/ee/security/reset_user_password.html#reset-your-root-password.

Password: LYwmW7opZs83gZpfv61ub6xnpV/Rxzekd+nKTUONPCM=

# NOTE: This file will be automatically deleted in the first reconfigure run after 24 hours.

成功登录界面

配置钉钉登录

创建钉钉应用

# 参考文档
https://open.dingtalk.com/document/isvapp/create-an-application

获取密钥信息

配置回调域名

http://<Gitlab_url>/users/auth/dingtalk/callback

编辑配置文件

root@ecs-e58f:~# vim /etc/gitlab/gitlab.rb

# 添加如下配置
gitlab_rails['omniauth_auto_link_ldap_user'] = true
gitlab_rails['omniauth_allow_single_sign_on'] = ['dingtalk']
gitlab_rails['omniauth_sync_email_from_provider'] = 'dingtalk'
gitlab_rails['omniauth_sync_profile_from_provider'] = ['dingtalk']
gitlab_rails['omniauth_sync_profile_attributes'] = ['name','email','location']
gitlab_rails['omniauth_providers'] = [
{
name: "dingtalk",
# 登录按钮展示名称
label: "钉钉",
app_id: "dingxkrixr7yny3qauzn",
app_secret: "l3c6rKxpeV3ZYT9AUEsw8D2Y9xh_bQBrZ4ICUfVLMGL4xSS-LP6xM8ebGJZg23sl"
}
]

# 重新加载配置文件
root@ecs-e58f:~# gitlab-ctl reconfigure

访问gitlab

如上所示,登录选项多了钉钉选项。

点击跳转至扫码登录界面

出现如下信息即可:

审批

登录管理员账号审批同意钉钉登录用户

钉钉用户登录

审批完成后,返回扫码登录
登录成功,设置个人信息后可正常使用。

⚠注意

文中所涉及云服务器以及钉钉应用均已删除。

Linux常用排查命令

· 9 min read
1cobot
开发者

查看 socket buffer

查看是否阻塞

root@ubuntu:~# netstat -antup | awk '{if($2>100||$3>100){print $0}}'
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
  • Recv-Q 是接收队列,如果持续有堆积,可能是高负载,应用处理不过来,也可能是程序的 bug,卡住了,导致没有从 buffer 中取数据,可以看看对应 pid 的 stack 卡在哪里了(cat /proc/$PID/stack)。

查看是否有 UDP buffer 满导致丢包

# 使用 netstat 查看统计
root@ubuntu:~# netstat -s | grep "buffer errors"
0 receive buffer errors
0 send buffer errors

# 也可以用 nstat 查看计数器
root@ubuntu:~# nstat -az | grep -E 'UdpRcvbufErrors|UdpSndbufErrors'
UdpRcvbufErrors 0 0.0
UdpSndbufErrors 0 0.0

对于 TCP,发送 buffer 慢不会导致丢包,只是会让程序发送数据包时卡住,等待缓冲区有足够空间释放出来,而接收 buffer 满了会导致丢包,可以通过计数器查看:

root@ubuntu:~# nstat -az | grep TcpExtTCPRcvQDrop
TcpExtTCPRcvQDrop 0 0.0

查看当前 UDP buffer 的情况

root@ubuntu:~# ss -nump
Recv-Q Send-Q Local Address:Port Peer Address:Port Process
0 0 10.10.4.26%eth0:68 10.10.4.1:67 users:(("NetworkManager",pid=960,fd=22))
skmem:(r0,rb212992,t0,tb212992,f0,w0,o640,bl0,d0)
  • rb212992 表示 UDP 接收缓冲区大小是 212992 字节,tb212992 表示 UDP 发送缓存区大小是 212992 字节。
  • Recv-Q 和 Send-Q 分别表示当前接收和发送缓冲区中的数据包字节数。

查看当前 TCP buffer 的情况

root@ubuntu:~# ss -ntmp
State Recv-Q Send-Q Local Address:Port Peer Address:Port Process
ESTAB 0 36 192.168.91.47:22 192.168.91.199:7916 users:(("sshd",pid=1327,fd=4))
skmem:(r0,rb131072,t0,tb87040,f2780,w1316,o0,bl0,d0)
ESTAB 0 0 192.168.91.47:22 192.168.91.199:7917 users:(("sshd",pid=1468,fd=4))
skmem:(r0,rb131072,t0,tb87040,f4096,w0,o0,bl0,d0)
  • rb131072 表示 TCP 接收缓冲区大小是 131072 字节,tb87040 表示 TCP 发送缓存区大小是 87040 字节。
  • Recv-Q 和 Send-Q 分别表示当前接收和发送缓冲区中的数据包字节数。

查看监听队列

root@ubuntu:~# ss -lnt
State Recv-Q Send-Q Local Address:Port Peer Address:Port Process
LISTEN 0 4096 127.0.0.53%lo:53 0.0.0.0:*
LISTEN 0 128 0.0.0.0:22 0.0.0.0:*
LISTEN 0 128 127.0.0.1:6010 0.0.0.0:*
LISTEN 0 128 [::]:22 [::]:*
LISTEN 0 128 [::1]:6010 [::]:*

Recv-Q 表示 accept queue 中的连接数,如果满了(Recv-Q的值比Send-Q大1),要么是并发太大,或负载太高,程序处理不过来;要么是程序 bug,卡住了,导致没有从 accept queue 中取连接,可以看看对应 pid 的 stack 卡在哪里了(cat /proc/$PID/stack)。

查看网络计数器

root@ubuntu:~# nstat -az
#kernel
IpInReceives 25253 0.0
IpInHdrErrors 0 0.0
IpInAddrErrors 0 0.0
IpForwDatagrams 0 0.0
IpInUnknownProtos 0 0.0
IpInDiscards 0 0.0
IpInDelivers 25253 0.0
IpOutRequests 11348 0.0
IpOutDiscards 20 0.0
IpOutNoRoutes 0 0.0
IpReasmTimeout 0 0.0
......

root@ubuntu:~# netstat -s | grep -E 'drop|overflow'
20 outgoing packets dropped

如果有 overflow,意味着 accept queue 有满过,可以查看监听队列看是否有现场。

查看 conntrack

# install
root@ubuntu:~# apt install -y conntrack

root@ubuntu:~# conntrack -S
cpu=0 found=0 invalid=0 ignore=0 insert=0 insert_failed=0 drop=0 early_drop=0 error=0 search_restart=0
cpu=1 found=0 invalid=0 ignore=0 insert=0 insert_failed=0 drop=0 early_drop=0 error=0 search_restart=0
cpu=2 found=0 invalid=0 ignore=0 insert=0 insert_failed=0 drop=0 early_drop=0 error=0 search_restart=0
cpu=3 found=0 invalid=0 ignore=0 insert=0 insert_failed=0 drop=0 early_drop=0 error=0 search_restart=0
cpu=4 found=0 invalid=0 ignore=0 insert=0 insert_failed=0 drop=0 early_drop=0 error=0 search_restart=0
cpu=5 found=0 invalid=0 ignore=0 insert=0 insert_failed=0 drop=0 early_drop=0 error=0 search_restart=0
cpu=6 found=0 invalid=0 ignore=0 insert=0 insert_failed=0 drop=0 early_drop=0 error=0 search_restart=0
cpu=7 found=0 invalid=0 ignore=0 insert=0 insert_failed=0 drop=0 early_drop=0 error=0 search_restart=0
cpu=8 found=0 invalid=0 ignore=0 insert=0 insert_failed=0 drop=0 early_drop=0 error=0 search_restart=0
cpu=9 found=0 invalid=0 ignore=0 insert=0 insert_failed=0 drop=0 early_drop=0 error=0 search_restart=0
cpu=10 found=0 invalid=0 ignore=0 insert=0 insert_failed=0 drop=0 early_drop=0 error=0 search_restart=0
......
  • 若有 insert_failed,表示存在 conntrack 插入失败,会导致丢包。

查看连接数

如果有 ss 命令,可以使用 ss -s 统计

root@ubuntu:~# ss -s
Total: 156
TCP: 7 (estab 2, closed 0, orphaned 0, timewait 0)

Transport Total IP IPv6
RAW 1 0 1
UDP 1 1 0
TCP 7 5 2
INET 9 6 3
FRAG 0 0 0

如果没有 ss,也可以尝试用脚本统计当前各种状态的 TCP 连接数:

root@ubuntu:~# netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}'
ESTABLISHED 2

或者直接手动统计 /proc

root@ubuntu:~# cat /proc/net/tcp* | wc -l
9

测试网络连通性

不断 telnet 查看网络是否能通

root@ubuntu:~# while true; do echo "" | telnet 192.168.91.47 443; sleep 0.1; done
Trying 192.168.91.47...
telnet: Unable to connect to remote host: Connection refused
Trying 192.168.91.47...
telnet: Unable to connect to remote host: Connection refused
Trying 192.168.91.47...
telnet: Unable to connect to remote host: Connection refused
Trying 192.168.91.47...
telnet: Unable to connect to remote host: Connection refused
Trying 192.168.91.47...
telnet: Unable to connect to remote host: Connection refused
Trying 192.168.91.47...
telnet: Unable to connect to remote host: Connection refused
Trying 192.168.91.47...
telnet: Unable to connect to remote host: Connection refused
Trying 192.168.91.47...
telnet: Unable to connect to remote host: Connection refused
Trying 192.168.91.47...
telnet: Unable to connect to remote host: Connection refused
  • ctrl+c 终止测试
  • 替换 192.168.91.47443 为需要测试的 IP/域名 和端口

没有安装 telnet,也可以使用 nc 测试

root@ubuntu:~# nc -vz 192.168.91.47 443
nc: connect to 192.168.91.47 port 443 (tcp) failed: Connection refused

排查流量激增

iftop纠出大流量IP

# install
root@ubuntu:~# apt install -y iftop

root@ubuntu:~# iftop
ubuntu => 192.168.91.199 736b 838b 955b
<= 208b 208b 243b

netstat查看大流量IP连接

root@ubuntu:~# netstat -np | grep 192.168.91.47
tcp 0 36 192.168.91.47:22 192.168.91.199:7916 ESTABLISHED 1327/sshd: root@pts
tcp 0 0 192.168.91.47:22 192.168.91.199:7917 ESTABLISHED 1468/sshd: root@not

排查资源占用

文件被占用

看某个文件在被哪些进程读写

root@ubuntu:~# lsof <filename>

看某个进程打开了哪些文件

root@ubuntu:~# lsof -p <pid>

端口占用

查看 22 端口被谁占用

root@ubuntu:~# lsof -i :22
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
sshd 1084 root 3u IPv4 37331 0t0 TCP *:ssh (LISTEN)
sshd 1084 root 4u IPv6 37333 0t0 TCP *:ssh (LISTEN)
sshd 1327 root 4u IPv4 40063 0t0 TCP ubuntu:ssh->192.168.91.199:7916 (ESTABLISHED)
sshd 1468 root 4u IPv4 40259 0t0 TCP ubuntu:ssh->192.168.91.199:7917 (ESTABLISHED)

或者

root@ubuntu:~# netstat -tunlp | grep 22
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 1084/sshd: /usr/sbi
tcp6 0 0 :::22 :::* LISTEN 1084/sshd: /usr/sbi

查看进程树

root@ubuntu:~# pstree
systemd─┬─VGAuthService
├─accounts-daemon───2*[{accounts-daemon}]
├─agetty
├─atd
├─cron
├─dbus-daemon
├─irqbalance───{irqbalance}
├─multipathd───6*[{multipathd}]
├─networkd-dispat
├─polkitd───2*[{polkitd}]
├─rsyslogd───3*[{rsyslogd}]
├─snapd───12*[{snapd}]
├─sshd─┬─sshd───bash─┬─iftop───3*[{iftop}]
│ │ └─pstree
│ └─sshd───sftp-server
├─systemd───(sd-pam)
├─systemd-journal
├─systemd-logind
├─systemd-network
├─systemd-resolve
├─systemd-timesyn───{systemd-timesyn}
├─systemd-udevd
├─udisksd───4*[{udisksd}]
├─unattended-upgr───{unattended-upgr}
└─vmtoolsd───2*[{vmtoolsd}]

测试对比 CPU 性能

看计算圆周率耗时,耗时越短说明 CPU 性能越强

root@ubuntu:~# time echo "scale=5000; 4*a(1)"| bc -l -q
3.141592653589793238462643383279502884197169399375105820974944592307\
81640628620899862803482534211706798214808651328230664709384460955058\
22317253594081284811174502841027019385211055596446229489549303819644\
28810975665933446128475648233786783165271201909145648566923460348610\
45432664821339360726024914127372458700660631558817488152092096282925\
......

real 0m11.704s
user 0m11.689s
sys 0m0.004s

查看证书内容

查看 secret 里的证书内容

root@ubuntu:~# kubectl get secret test-crt-secret  -o jsonpath='{.data.tls\.crt}' | base64 -d | openssl x509 -noout -text

查看证书文件内容

root@ubuntu:~# openssl x509 -noout -text -in test.crt

查看远程地址的证书内容

root@ubuntu:~# echo | openssl s_client -connect 192.168.91.47:443 2>/dev/null | openssl x509 -noout -text

磁盘占用

空间占用

root@ubuntu:~# df -h
Filesystem Size Used Avail Use% Mounted on
udev 1.9G 0 1.9G 0% /dev
tmpfs 391M 1.3M 390M 1% /run
/dev/mapper/ubuntu--vg-ubuntu--lv 59G 6.3G 50G 12% /
tmpfs 2.0G 0 2.0G 0% /dev/shm
tmpfs 5.0M 0 5.0M 0% /run/lock
tmpfs 2.0G 0 2.0G 0% /sys/fs/cgroup
/dev/loop0 33M 33M 0 100% /snap/snapd/12704
/dev/loop1 71M 71M 0 100% /snap/lxd/21029
/dev/loop2 56M 56M 0 100% /snap/core18/2128
/dev/sda2 976M 107M 803M 12% /boot
/dev/loop3 56M 56M 0 100% /snap/core18/2812
tmpfs 391M 0 391M 0% /run/user/0

inode占用

root@ubuntu:~# df -i
Filesystem Inodes IUsed IFree IUse% Mounted on
udev 488931 476 488455 1% /dev
tmpfs 500220 771 499449 1% /run
/dev/mapper/ubuntu--vg-ubuntu--lv 3899392 80416 3818976 3% /
tmpfs 500220 1 500219 1% /dev/shm
tmpfs 500220 3 500217 1% /run/lock
tmpfs 500220 18 500202 1% /sys/fs/cgroup
/dev/loop0 474 474 0 100% /snap/snapd/12704
/dev/loop1 1602 1602 0 100% /snap/lxd/21029
/dev/loop2 10803 10803 0 100% /snap/core18/2128
/dev/sda2 65536 312 65224 1% /boot
/dev/loop3 10944 10944 0 100% /snap/core18/2812
tmpfs 500220 22 500198 1% /run/user/0

或者

root@ubuntu:~# tune2fs -l /dev/sda2 | grep -i inode
Filesystem features: has_journal ext_attr resize_inode dir_index filetype needs_recovery extent 64bit flex_bg sparse_super large_file huge_file dir_nlink extra_isize metadata_csum
Inode count: 65536
Free inodes: 65224
Inodes per group: 8192
Inode blocks per group: 512
First inode: 11
Inode size: 256
Journal inode: 8
Journal backup: inode blocks

kubernetes安装NFS CSI Driver

· 3 min read
1cobot
开发者

安装NFS-SERVER

在kubernetes中集群安装部署一个nfs-server prod

参考: Set up a NFS Server on a Kubernetes cluster

# 下载安装文件
[root@master nfs]# wget https://raw.githubusercontent.com/kubernetes-csi/csi-driver-nfs/master/deploy/example/nfs-provisioner/nfs-server.yaml

# 安装资源对象
[root@master nfs]# kubectl apply -f nfs-server.yaml

# 查看POD状态
[root@master nfs]# kubectl get pods
NAME READY STATUS RESTARTS AGE
nfs-server-5847b99d99-l222n 1/1 Running 0 13m

安装NFS-CSI

参考: Install NFS CSI driver on a kubernetes cluster

Install with kubectl

[root@master nfs]# curl -skSL https://raw.githubusercontent.com/kubernetes-csi/csi-driver-nfs/v4.2.0/deploy/install-driver.sh | bash -s v4.2.0 --
Installing NFS CSI driver, version: v4.2.0 ...
serviceaccount/csi-nfs-controller-sa configured
serviceaccount/csi-nfs-node-sa configured
clusterrole.rbac.authorization.k8s.io/nfs-external-provisioner-role configured
clusterrolebinding.rbac.authorization.k8s.io/nfs-csi-provisioner-binding configured
csidriver.storage.k8s.io/nfs.csi.k8s.io configured
deployment.apps/csi-nfs-controller created
daemonset.apps/csi-nfs-node created
NFS CSI driver installed successfully.

clean up NFS CSI driver

[root@master nfs]# curl -skSL https://raw.githubusercontent.com/kubernetes-csi/csi-driver-nfs/v4.2.0/deploy/uninstall-driver.sh | bash -s v4.2.0 --

查看pod状态

[root@master nfs]# kubectl -n kube-system get pods 
NAME READY STATUS RESTARTS AGE
coredns-7b5dd5fb4-7dt6v 1/1 Running 1 (145m ago) 47h
coredns-7b5dd5fb4-br2vk 1/1 Running 1 (145m ago) 47h
csi-nfs-controller-d4ff49ff5-vj8rm 0/3 ContainerCreating 0 110s
csi-nfs-node-7p9t7 0/3 ErrImagePull 0 107s
csi-nfs-node-js92p 0/3 ContainerCreating 0 107s
csi-nfs-node-jwqgn 0/3 ErrImagePull 0 107s
csi-nfs-node-ppbdj 0/3 ErrImagePull 0 107s
csi-nfs-node-qzzsn 0/3 ErrImagePull 0 107s
csi-nfs-node-v8xx9 0/3 ErrImagePull 0 107s

修改镜像为国内镜像( registry.k8s.io --> uhub.service.ucloud.cn )

tip

可使用ucloud的镜像加速功能

[root@master nfs]# kubectl -n kube-system edit deployments.apps csi-nfs-controller 
deployment.apps/csi-nfs-controller edited

[root@master nfs]# kubectl -n kube-system edit daemonsets.apps csi-nfs-node
daemonset.apps/csi-nfs-node edited
# 再次查看pod状态
[root@master nfs]# kubectl -n kube-system get pods -w
NAME READY STATUS RESTARTS AGE
coredns-7b5dd5fb4-7dt6v 1/1 Running 1 (154m ago) 47h
coredns-7b5dd5fb4-br2vk 1/1 Running 1 (154m ago) 47h
csi-nfs-controller-7c78cc596b-9sm7s 3/3 Running 0 5m53s
csi-nfs-node-5vgql 0/3 ContainerCreating 0 2s
csi-nfs-node-jx79k 0/3 ContainerCreating 0 1s
csi-nfs-node-n4cl9 0/3 ContainerCreating 0 1s
csi-nfs-node-sb7fw 0/3 ContainerCreating 0 2s
csi-nfs-node-w5gpx 0/3 ContainerCreating 0 1s
csi-nfs-node-zg58g 0/3 ContainerCreating 0 2s

创建storage class

参考:storageclass-nfs.yaml

---
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: nfs-csi
provisioner: nfs.csi.k8s.io
parameters:
server: nfs-server.default.svc.cluster.local
share: /
# csi.storage.k8s.io/provisioner-secret is only needed for providing mountOptions in DeleteVolume
# csi.storage.k8s.io/provisioner-secret-name: "mount-options"
# csi.storage.k8s.io/provisioner-secret-namespace: "default"
reclaimPolicy: Delete
volumeBindingMode: Immediate
mountOptions:
- nfsvers=4.1

创建资源对象:

[root@master nfs]# kubectl apply -f csi-nfs-sc.yaml 
storageclass.storage.k8s.io/nfs-csi created

# 查看资源对象
[root@master nfs]# kubectl get sc
NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGE
nfs-csi nfs.csi.k8s.io Delete Immediate false 46s
danger

此次实验最终并未自动创建pvc,原因待查。

nsenter命令的使用

· 2 min read
1cobot
开发者

nsenter简介

nsenter命令是一个可以在指定进程的命令空间下运行指定程序的命令。它位于util-linux包中。

我们使用 Kubernetes 时难免发生一些网络问题,往往需要进入容器的网络命名空间 (netns) 中,进行一些网络调试来定位问题,本文介绍如何进入容器的 netns。

排查步骤

获取容器的ID

root@master01:~# kubectl describe pods nginx-demo-65df8cb4c4-zbckd 

Containers:
nginx:
Container ID: containerd://d9ec0a5a912e0b6e21b76b86c2e02c114a3906e2cb87e3de3b84ec1e93b43c54

获取PID

拿到 container id 后,查询 pod 所在节点,去获取其主进程 pid

# 查看pod所在节点
root@master01:~# kubectl get pods -owide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx-demo-65df8cb4c4-zbckd 1/1 Running 0 10m 10.244.2.8 node03 <none> <none>

# 查询主进程pid
root@node03:~# nerdctl inspect d9ec0a5a912e0b6e21b76b86c2e02c114a3906e2cb87e3de3b84ec1e93b43c54 | grep -i pid
"Pid": 4361,

使用nsenter命令进入容器的netns

root@node03:~# nsenter -n -t 4361

调试网络

成功进入容器的 netns,可以使用节点上的网络工具进行调试网络,可以首先使用 ip a 验证下 ip 地址是否为 pod ip:

root@node03:~# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: eth0@if6: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue state UP group default
link/ether ea:e0:56:fc:84:40 brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet 10.244.2.8/24 brd 10.244.2.255 scope global eth0
valid_lft forever preferred_lft forever
inet6 fe80::e8e0:56ff:fefc:8440/64 scope link
valid_lft forever preferred_lft forever

Ubuntu20.04安装vsftpd

· 4 min read
1cobot
开发者

修改主机名

root@ubuntu:~# hostnamectl set-hostname vsftpd

更新软件源

root@vsftpd:~# apt update

安装vsftpd服务

# 安装
root@vsftpd:~# apt install -y vsftpd

# 查看服务状态
root@vsftpd:~# systemctl status vsftpd.service
● vsftpd.service - vsftpd FTP server
Loaded: loaded (/lib/systemd/system/vsftpd.service; enabled; vendor preset: enabled)
Active: active (running) since Wed 2024-05-15 13:26:54 UTC; 29s ago
Main PID: 3057 (vsftpd)
Tasks: 1 (limit: 4583)
Memory: 820.0K
CGroup: /system.slice/vsftpd.service
└─3057 /usr/sbin/vsftpd /etc/vsftpd.conf

May 15 13:26:54 vsftpd systemd[1]: Starting vsftpd FTP server...
May 15 13:26:54 vsftpd systemd[1]: Started vsftpd FTP server.

设置访问用户

在FTP安装完成后,会默认为我们创建用户名为ftp的用户,默认无密码.

# 为ftp用户设置密码
root@vsftpd:~# passwd ftp
New password:
Retype new password:
passwd: password updated successfully

# 创建ftp用户的家目录,即ftp文件的存储路径
root@vsftpd:~# mkdir /home/ftp

# 设置ftp目录的权限
root@vsftpd:~# chmod 777 /home/ftp

配置FTP服务

配置文件存放路径:

/etc/vsftpd.conf

修改如下:

#取消如下配置前的注释符号:
local_enable=YES(是否允许本地用户登录)
write_enable=YES(是否允许本地用户写的权限)
chroot_local_user=YES(是否将所有用户限制在主目录)
chroot_list_enable=YES(是否启动限制用户的名单)
chroot_list_file=/etc/vsftpd.chroot_list(可在文件中设置多个账号)
#修改如下配置
anonymous_enable=NO (不允许匿名访问,必须登录)
chown_uploads=YES (允许上传改变)
#并且添加如下内容
local_root=/home/ftp (访问目录)
allow_writeable_chroot=YES

同时在/etc下创建vsftpd.chroot_list文件,这个文件创建完成保持为空即可

root@vsftpd:~# touch /etc/vsftpd.chroot_list

重启服务

root@vsftpd:~# systemctl restart vsftpd.service 
root@vsftpd:~# systemctl status vsftpd.service
● vsftpd.service - vsftpd FTP server
Loaded: loaded (/lib/systemd/system/vsftpd.service; enabled; vendor preset: enabled)
Active: active (running) since Wed 2024-05-15 13:36:08 UTC; 1s ago
Process: 3791 ExecStartPre=/bin/mkdir -p /var/run/vsftpd/empty (code=exited, status=0/SUCCESS)
Main PID: 3801 (vsftpd)
Tasks: 1 (limit: 4583)
Memory: 740.0K
CGroup: /system.slice/vsftpd.service
└─3801 /usr/sbin/vsftpd /etc/vsftpd.conf

May 15 13:36:08 vsftpd systemd[1]: Starting vsftpd FTP server...
May 15 13:36:08 vsftpd systemd[1]: Started vsftpd FTP server.

测试

root@vsftpd:~# ftp localhost
Connected to localhost.
220 (vsFTPd 3.0.5)
Name (localhost:root): ftp
331 Please specify the password.
Password:
530 Login incorrect.
Login failed.
ftp>

如果登录ftp总是出现密码错误,可以将/etc/vsftpd.conf配置文件的pam_service_name=vsftpd改为pam_service_name=ftp,即可解决。

pam_service_name=ftp

修改完成之后再次重启服务,测试如下:

root@vsftpd:~# ftp localhost
Connected to localhost.
220 (vsFTPd 3.0.5)
Name (localhost:root): ftp
331 Please specify the password.
Password:
230 Login successful.
Remote system type is UNIX.
Using binary mode to transfer files.
ftp>

FTP客户端测试

这里使用filezilla演示:
新建连接站点:

弹出提示,点击信任进入下一步:

随即登录成功:

创建文件测试:

通过Linux服务端查看文件是否存在:

root@vsftpd:~# cd /home/ftp/
root@vsftpd:/home/ftp# ls
windows_client
root@vsftpd:/home/ftp#

tcpdump抓包与分析

· 2 min read
1cobot
开发者

抓包基础

# 安装tcpdump
[root@localhost ~]# yum install -y tcpdump

# 抓包内容实时显示到控制台
# 这个命令的意思是在网络接口 eth0 上捕获发送或接收到目标主机 IP 地址为 192.168.91.41 的所有数据包,并以可读的日期和时间的格式显示时间戳。
[root@localhost ~]# tcpdump -i eth0 host 192.168.91.41 -nn -tttt

# 抓包内容实时显示到控制台
[root@localhost ~]# tcpdump -i eth0 host 192.168.91.41 -nn -tttt
[root@localhost ~]# tcpdump -i any host 192.168.91.41 -nn -tttt
[root@localhost ~]# tcpdump -i any host 192.168.91.41 and port 8088 -nn -tttt
# 抓包存到文件
[root@localhost ~]# tcpdump -i eth0 -w test.pcap
# 读取抓包内容
[root@localhost ~]# tcpdump -r test.pcap -nn -tttt
常用参数

-r: 指定包文件。
-nn: 显示数字ip和端口,不转换成名字。
-tttt: 显示时间戳格式: 2006-01-02 15:04:05.999999

轮转抓包

# 每100M轮转一次,最多保留200个文件 (推荐,文件大小可控,可通过文件修改时间判断报文时间范围)
[root@localhost ~]# tcpdump -i eth0 port 8880 -w cvm.pcap -C 100 -W 200

# 每2分钟轮转一次,后缀带上时间
[root@localhost ~]# tcpdump -i eth0 port 31780 -w node-10.70.10.101-%Y-%m%d-%H%M-%S.pcap -G 120

过滤连接超时的包(reset)

一般如果有连接超时发生,一般 client 会发送 reset 包,可以过滤下:

[root@localhost ~]# tcpdump -r test.pcap 'tcp[tcpflags] & (tcp-rst) != 0' -nn -ttt

统计流量源IP

[root@localhost ~]# tcpdump -i eth0 dst port 60002 -c 10000|awk '{print $3}'|awk -F. -v OFS="." '{print $1,$2,$3,$4}'|sort |uniq -c|sort -k1 -n

docusaurus代码块使用

· 2 min read
1cobot
开发者

在 Docusaurus 中实现代码块的多个选项卡可以使用其提供的 TabsTabItem 组件。这些组件允许你创建一个选项卡式的界面,并在不同选项卡中展示不同的代码块或内容。

实现步骤

  • 使用 Tabs 组件包裹不同的 TabItem 组件。
  • 在每个 TabItem 中放置对应的代码块或内容。

下面是一个示例,展示如何实现多语言的代码选项卡(比如 JavaScriptPython ):

function helloWorld() {
console.log("Hello, World!");
}

说明

  • value:每个 TabItem 的唯一标识符,用于区分不同的选项卡。
  • label:选项卡上显示的文本标签。
  • 代码块中的语言标识符(如 javascriptpython)将启用相应的语法高亮。

效果

这种方法可以创建一个界面,其中每个选项卡对应不同的编程语言或内容,并且用户可以通过点击不同的选项卡来查看不同的代码块。