juju创建lxd容器时如何使用本地镜像(by quqi99)
作者:张华 发表于:2023-03-01
版权声明:可以任意转载,转载时请务必以超链接形式标明文章原始出处和作者信息及本版权声明
问题
没有外网,所以配置了一个local custom镜像库,也使用了container-image-metadata-url进行配置,但是用juju创建lxd容器时还是说找不着image.
相关搜索
关于container-image-metadata-url的代码如下:
https://github.com/juju/juju/pull/8578
https://github.com/juju/juju/blob/juju-2.9.35/container/lxd/manager.go#L282-L284
也有一个好帖子:
https://discourse.charmhub.io/t/local-lxd-image-server/3929/5
实验环境
1, 使用 juju创建一个focal的machine 0, 然后再machine 0上部署一个xenial的lxd容器。
juju add-model test
juju add-machine --series focal
juju model-config logging-config="<root>=DEBUG"
juju remove-application ceph-radosgw && juju deploy ceph-radosgw --series=xenial --to="lxd:0"
2, 在juju controller(juju ssh -m controller 0)与machine 0上运行下列iptables来模拟和cloud-images.ubuntu.com断网。这里我发现:
- machine 0的日志(/var/log/juju/machine-0.log)显示它好像是从juju controller处下载镜像的
2023-03-01 07:58:21 INFO juju.cloudconfig userdatacfg_unix.go:613 Fetching agent: curl -sSf --connect-timeout 20 --noproxy "*" --insecure -o $bin/tools.tar.gz <[https://10.5.0.31:17070/model/deb85179-10a6-4877-88f7-012ef768d726/tools/2.9.38-ubuntu-amd64 https://252.0.31.1:17070/model/deb85179-10a6-4877-88f7-012ef768d726/tools/2.9.38-ubuntu-amd64]>
2023-03-01 07:59:03 INFO juju.container.lxd container.go:256 starting new container "juju-68d726-0-lxd-2" (image "ubuntu-16.04-server-cloudimg-amd64-lxd.tar.xz")
2023-03-01 07:59:03 DEBUG juju.container.lxd container.go:257 new container has profiles [default]
2023-03-01 07:59:42 DEBUG juju.container.lxd container.go:286 created container "juju-68d726-0-lxd-2", waiting for start...
- 但如果不在machine 0上运行下载iptables,测试表明machine0也能直接扰开juju controller从cloud-images.ubuntu.com处下镜像.
- 似乎二者均相关,那就二者将运行下列iptables吧
dig cloud-images.ubuntu.com #185.125.190.37 and 185.125.190.40
iptables -A OUTPUT -d 185.125.190.37 -j DROP
iptables -A OUTPUT -d 185.125.190.40 -j DROP
3, bastion上运行sstream-mirror将cloud-images.ubuntu.com中的xenial amd64镜像mirror了下来。
sudo apt -y install simplestreams -y
workdir=/home/ubuntu/simplestreams2
sudo sstream-mirror --keyring=/usr/share/keyrings/ubuntu-cloudimage-keyring.gpg --progress --max=1 --path=streams/v1/index.json https://cloud-images.ubuntu.com/releases/ $workdir 'arch=amd64' 'release~(xenial)' 'ftype~(lxd.tar.xz|squashfs|root.tar.xz|root.tar.gz|disk1.img|.json|.sjson)'
然后用nginx为它配置了https:
#https://goharbor.io/docs/2.6.0/install-config/configure-https/
openssl genrsa -out ca.key 4096
openssl req -x509 -new -nodes -sha512 -days 3650 -subj "/C=CN/ST=Beijing/L=Beijing/O=example/OU=Personal/CN=quqi.com" -key ca.key -out ca.crt
openssl genrsa -out quqi.com.key 4096
openssl req -sha512 -new -subj "/C=CN/ST=Beijing/L=Beijing/O=example/OU=Personal/CN=quqi.com" -key quqi.com.key -out quqi.com.csr
#complies with the Subject Alternative Name (SAN) and x509 v3 extension requirements to avoid 'x509: certificate relies on legacy Common Name field, use SANs instead'
cat > v3.ext <<-EOF
authorityKeyIdentifier=keyid,issuer
basicConstraints=CA:FALSE
keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment
extendedKeyUsage = serverAuth
subjectAltName = @alt_names[alt_names]
DNS.1=quqi.com
DNS.2=quqi
DNS.3=hostname
EOF
openssl x509 -req -sha512 -days 3650 -extfile v3.ext -CA ca.crt -CAkey ca.key -CAcreateserial -in quqi.com.csr -out quqi.com.crt
#for docker, the Docker daemon interprets .crt files as CA certificates and .cert files as client certificates.
openssl x509 -inform PEM -in quqi.com.crt -out quqi.com.cert
curl --resolve quqi.com:443:10.5.0.126 --cacert ~/ca/ca.crt https://quqi.com:443/streams/v1/index.json
sudo cp ~/ca/ca.crt /usr/local/share/ca-certificates/ca.crt
sudo chmod 644 /usr/local/share/ca-certificates/ca.crt
sudo update-ca-certificates --fresh
curl --resolve quqi.com:443:10.5.0.126 https://quqi.com:443/streams/v1/index.json$ cat /etc/nginx/sites-available/default
server {listen 443 ssl http2;listen [::]:443 ssl http2;server_name quqi.com;ssl_certificate /home/ubuntu/ca/quqi.com.crt;ssl_certificate_key /home/ubuntu/ca/quqi.com.key;ssl_protocols TLSv1.2;ssl_prefer_server_ciphers on; location / {root /home/ubuntu/simplestreams2;index index.html;}
}
# 注意:由于上面使用了一个新目录/home/ubuntu/simplestreams2作为root,那需要将/etc/nginx/nginx.conf中添加'user root;'来避免权限问题
#curl --resolve quqi.com:443:10.5.0.126 --cacert ~/ca/ca.crt https://quqi.com:443/images/streams/v1/index.json
curl --resolve quqi.com:443:10.5.0.126 --cacert ~/ca/ca.crt https://quqi.com:443/streams/v1/index.json
4, 配置juju中的container-image-metadata-url使用上面的https based local image mirror
juju model-config container-image-metadata-url=https://quqi.com:443
juju model-config image-metadata-url=https://quqi.com:443
5, juju controller由于访问local image mirror, 所以配置hosts与添加ca key
echo '10.5.0.126 quqi.com' >> /etc/hostscurl --resolve quqi.com:443:10.5.0.126 --cacert ~/ca/ca.crt https://quqi.com:443/streams/v1/index.json
sudo cp ~/ca/ca.crt /usr/local/share/ca-certificates/ca.crt
sudo chmod 644 /usr/local/share/ca-certificates/ca.crt
sudo update-ca-certificates --fresh
curl --resolve quqi.com:443:10.5.0.126 https://quqi.com:443/streams/v1/index.json
6, 记得重新测试之前将machine 0上的image cache删除
juju ssh 0 -- sudo lxc image delete juju/xenial/amd64
juju remove-application ceph-radosgw
7, 重新测试
juju deploy ceph-radosgw --series=xenial --to="lxd:0"
sudo tail -f /var/log/juju/machine-0.log
能在machine 0的/var/log/juju/machine-0.log中观察下列日志:
2023-03-01 08:26:45 WARNING juju.worker.lxdprovisioner provisioner_task.go:1371 machine 0/lxd/3 failed to start: acquiring LXD image: no matching image found
2023-03-01 08:26:45 WARNING juju.worker.lxdprovisioner provisioner_task.go:1410 failed to start machine 0/lxd/3 (acquiring LXD image: no matching image found), retrying in 10s (10 more attempts)
在juju controller上有时能搜到quqi, 有时候又不能,奇怪.
2023-02-23 07:33:52 WARNING juju.apiserver.provisioner provisioninginfo.go:801 encountered "https://quqi.com:443/images/streams/v1/streams/v1/index.json": Get "https://quqi.com:443/images/streams/v1/streams/v1/index.json": dial tcp 49.234.171.74:443: i/o timeout while getting published images metadata from image-metadata-url
2023-03-01 08:52:56 WARNING juju.environs.simplestreams datasource.go:184 Got error requesting "https://quqi.com:443/streams/v1/index.json": Get "https://quqi.com:443/streams/v1/index.json": x509: certificate relies on legacy Common Name field, use SANs instead
juju controller上仍然能看到cloud-images.ubuntu.com
2023-03-01 08:34:54 WARNING juju.apiserver.provisioner provisioninginfo.go:801 encountered "http://cloud-images.ubuntu.com/releases/streams/v1/index.sjson": Get "http://cloud-images.ubuntu.com/releases/streams/v1/index.sjson": dial tcp 185.125.190.37:80: i/o timeout while getting published images metadata from default ubuntu cloud images
使用glance中的image来提供simplestreams
上面是使用来提供simplestreams, 我们现在换用glance中的image来提供simplestreams继续测试 (不确定是否这种只适用于创建juju controller, 还是说也可以用于VM/LXD创建,试一下)
mkdir -p ~/simplestreams/images
IMAGE_ID=26751c0e-4282-415e-b8dc-a7a21d2f781d
SERIES=xenial
juju metadata generate-image -d ~/simplestreams -i $IMAGE_ID -s $SERIES -r RegionOne -u $OS_AUTH_URL
然后修改/etc/nginx/sites-available/default将上面测试用的/home/ubuntu/simplestreams2改成/home/ubuntu/simplestreams, 重启nginx之后, 设置container-image-metadata-url (注意:此时后面链接多出了/images)
juju model-config container-image-metadata-url=https://quqi.com:443/images
juju model-config image-metadata-url=https://quqi.com:443/images
为保证测试环境干净,我也在controller与machine0上运行了下列命令:
systemctl restart jujud-machine-0.service
然后重复测试后,问题依旧, controller上看到下列日志:
2023-03-01 10:29:32 WARNING juju.environs.simplestreams datasource.go:184 Got error requesting "https://streams.canonical.com/juju/tools/streams/v1/index.sjson": Get "https://streams.canonical.com/juju/tools/streams/v1/index.sjson": dial tcp 185.125.190.37:443: i/o timeout
2023-03-01 10:29:36 INFO juju.state addmachine.go:505 new machine "0/lxd/11" has preferred addresses: private "", public ""
2023-03-01 10:29:37 WARNING juju.apiserver.instancemutater lxdprofilewatcher.go:206 unit ceph-radosgw/11 has no machine id, start watching when machine id assigned.
2023-03-01 10:29:41 WARNING juju.apiserver.provisioner provisioninginfo.go:801 encountered index file has no data for cloud {stsstack http://10.230.19.53:5000/v3} not found while getting published images metadata from image-metadata-url
2023-03-01 10:30:11 WARNING juju.environs.simplestreams datasource.go:184 Got error requesting "http://cloud-images.ubuntu.com/releases/streams/v1/index2.sjson": Get "http://cloud-images.ubuntu.com/releases/streams/v1/index2.sjson": dial tcp 185.125.190.40:80: i/o timeout
2023-03-01 10:30:41 WARNING juju.environs.simplestreams datasource.go:184 Got error requesting "http://cloud-images.ubuntu.com/releases/streams/v1/index.sjson": Get "http://cloud-images.ubuntu.com/releases/streams/v1/index.sjson": dial tcp 185.125.190.37:80: i/o timeout
2023-03-01 10:30:41 WARNING juju.apiserver.provisioner provisioninginfo.go:801 encountered "http://cloud-images.ubuntu.com/releases/streams/v1/index.sjson": Get "http://cloud-images.ubuntu.com/releases/streams/v1/index.sjson": dial tcp 185.125.190.37:80: i/o timeout while getting published images metadata from default ubuntu cloud images
看样子和simplestreams类型无关。
测试cloudinit-userdata
即然与simplestreams类型无关,那我们将nginx再恢复之前的/home/ubuntu/simplestreams2
juju model-config container-image-metadata-url=https://quqi.com:443/
juju model-config image-metadata-url=https://quqi.com:443/
然后测试cloudinit-userdata, 这个是没问题的,可以作workaround
cat << EOF |tee cloudinit-userdata.yaml
cloudinit-userdata: |postruncmd:- echo '10.5.0.126 quqi.com' >> /etc/hosts- if hostname |grep -qv lxd; then wget --tries=15 --retry-connrefused --timeout=15 --random-wait=on -O /home/ubuntu/ubuntu-16.04-server-cloudimg-amd64-lxd.tar.xz https://quqi.com:443/server/releases/xenial/release-20211001/ubuntu-16.04-server-cloudimg-amd64-lxd.tar.xz --no-check-certificate; wget --tries=15 --retry-connrefused --timeout=15 --random-wait=on -O /home/ubuntu/ubuntu-16.04-server-cloudimg-amd64.squashfs https://quqi.com:443/server/releases/xenial/release-20211001/ubuntu-16.04-server-cloudimg-amd64.squashfs --no-check-certificate; fi- sleep 30- if hostname |grep -qv lxd; then lxc image import /home/ubuntu/ubuntu-16.04-server-cloudimg-amd64-lxd.tar.xz /home/ubuntu/ubuntu-16.04-server-cloudimg-amd64.squashfs --alias juju/xenial/amd64; fi
EOF
juju model-config ./cloudinit-userdata.yaml
juju model-config cloudinit-userdata --format yaml
#juju model-config --reset cloudinit-userdata
注意:之前一直不work的原因是因为在postruncmd:后加了 | 的原因,找到答案的过程见下列的"调试cloud-init"一节。
调试cloud-init
最后发现用下面的是不work的:
cat << EOF |tee test.yaml
cloudinit-userdata: |postruncmd: |- echo '10.5.0.126 quqi.com' >> /etc/hosts- echo 'test' > /home/ubuntu/cloud-init.txt
EOF
需要改成下面的:
cat << EOF |tee test.yaml
cloudinit-userdata: |postruncmd:- bash -c 'echo 10.5.0.126 quqi.com >> /etc/hosts'- bash -c 'echo test > /home/ubuntu/cloud-init.txt'
EOF
下面的也不会work
cat << EOF |tee test.yaml
cloudinit-userdata: |postruncmd: |bash -c 'echo 10.5.0.126 quqi.com >> /etc/hosts'bash -c 'echo test > /home/ubuntu/cloud-init.txt'
EOF
下面的更不会work, 会直接报:ERROR json: unsupported type: map[interface {}]interface {}’
cat << EOF |tee test.yaml
cloudinit-userdata: |postruncmd:bash -c 'echo 10.5.0.126 quqi.com >> /etc/hosts'bash -c 'echo test > /home/ubuntu/cloud-init.txt'
EOF
其他调试方法如下:
juju add-model test
juju model-config ./test.yaml
juju model-config cloudinit-userdata --format yaml
juju add-machine --series focal1, check cloud-init log: cloud-init collect-logs & tar -xf cloud-init.tar.gz
2, check cloud-init config: /etc/cloud/cloud.cfg
3, cloud-init is enabled: systemctl list-unit-files | grep cloud
4, /var/lib/cloud/instances/af2d721e-e38e-4937-81ad-7cc72a49c184/cloud-config.txt
lp bug 1797168
试图排除https://bugs.launchpad.net/juju/+bug/1797168
juju add-model test2
juju model-config container-image-metadata-url=https://quqi.com:443/
juju model-config image-metadata-url=https://quqi.com:443/
juju model-config logging-config="<root>=DEBUG"
juju add-machine --series focal
juju remove-application ceph-radosgw && juju deploy ceph-radosgw --series=xenial --to="lxd:0"
但是也不行. 晕了。
相关文章:
juju创建lxd容器时如何使用本地镜像(by quqi99)
作者:张华 发表于:2023-03-01 版权声明:可以任意转载,转载时请务必以超链接形式标明文章原始出处和作者信息及本版权声明 问题 没有外网,所以配置了一个local custom镜像库,也使用了container-image-meta…...
后端程序员学习前端开发之第一步环境搭建
一、安装 Node.js Node.js 是一个开源的、跨平台的 JavaScript 运行时环境。Node.js官网 二、安装 npm 镜像 因为 npm 是国外的,所以使用起来速度比较慢。我们这里使用了淘宝的 cnpm 镜像安装 vue。使用淘宝的 cnpm 命令管理工具代替默认的 npm 管理工具。 进入c…...

【记录问题】RuntimeError:working outside of application context. Flask使用SQLAlchemy数据库
前提:Flask使用SQLAlchemy数据库 本质:依赖包版本不匹配 问题1:报错RuntimeError:working outside of application context. 运行程序报错,如下错误: 原因:flask-sqlalchemy 版本过高导致&am…...

自动化测试难点案例分析,其实自动化你用错方向还不如不用
随着国内企业软件开发及测试水平的提升,许多企业开始尝试开展自动化测试的应用,以提高测试效率和测试质量。虽然在国外自动化测试工具应用已经很普遍,但国内许多企业对于软件自动化测试的理解还停留在表面上,没有深入的理解到企业…...

866363-70-4,N3-C5-NHS ester,叠氮-C5-NHS 主要物理性质分享
●外观以及性质:Azido-Aca-NHS淡黄色或无色油状,叠氮化物可以与炔烃、DBCO和BCN进行铜催化的点击化学反应。NHS酯可以与胺基反应,形成稳定的酰胺键。●中文名:叠氮-C5-NHS ester,6-叠氮己酸活性酯●英文名:…...

字符流定义及如何深入理解字符流的编码
IputSrem类和OupuSrem类在读写文件时操作的都是字节,如果希望在程序中操作字符,使用这两个类就不太方便,为此JDK提供了字符流。同字节流样,字符流也有两个抽象的顶级父类,分别是Reader和Writer其中,Reader是…...

什么是pod类型
很久很久以前,C 语言统一了江湖。几乎所有的系统底层都是用 C 写的,当时定义的基本数据类型有 int、char、float 等整数类型、浮点类型、枚举、void、指针、数组、结构等等。然后只要碰到一串01010110010 之类的数据,编译器都可以正确的把它解…...

2023年中小企业实施智能制造的建议
智能制造的载体是制造系统,制造系统从微观到宏观有不同的层次,主要包括制造装备、制造单元、制造车间(工厂)、制造企业和企业生态等。随着智能制造的深入推进,未来智能制造将向以下五个方向发展。 (一&…...

【LeetCode】剑指 Offer 19. 正则表达式匹配 p124 -- Java Version
题目链接:https://leetcode.cn/problems/zheng-ze-biao-da-shi-pi-pei-lcof/ 1. 题目介绍(19. 正则表达式匹配) 请实现一个函数用来匹配包含. 和*的正则表达式。模式中的字符.表示任意一个字符,而’*表示它前面的字符可以出现任意…...

linux和windows中安装emqx消息服务器
大家好,我是雄雄,欢迎关注微信公众号雄雄的小课堂 现在是:2023年3月1日21:53:55 前言 最近几天看了下mqtt,通过不断的搜索资料,也将mqtt集成到项目中,跑了个demo运行,和预想中的差不多&#x…...

【XXL-JOB】XXL-JOB的搭建和使用
【XXL-JOB】XXL-JOB的搭建和使用 文章目录【XXL-JOB】XXL-JOB的搭建和使用1. 任务调度1.1 实现任务调度1.1.1 多线程实现1.1.2 Timer实现1.1.3 ScheduledExecutor实现2. 分布式任务调度2.1 采用分布式的原因3. XXL-JOB3.1 XXL-JOB介绍3.2 执行流程4. 搭建XXL-JOB4.1 创建数据库…...

HCIP-5OSPF基本原理及基本配置学习笔记
1、OSPF基本原理 开放式最短路径优先OSPF(Open Shortest Path First)协议是IETF定义的一种基于链路状态的内部网关路由协议。 RIP是一种基于距离矢量算法的路由协议,存在着收敛慢、易产生路由环路、可扩展性差等问题,目前已逐渐被…...
Migrate your data into databend with DataX
现在互联网应用越来越复杂,每个公司都会有多种多样的数据库。通常是用最好的硬件来跑 OLTP,甚至还在 OLTP 中进行分库分表来满足业务,这样对于一些分析,聚合,排序操作非常麻烦。这也有了异构数据库的数据同步需求&…...
ssh: Permission denied (publickey,gssapi-keyex,gssapi-with-mic,password)
【ansible 设置host为localhost,执行ping命令报错】 [eniq-slocalhost ansible]$ ansible all -m ping -i inventory localhost | UNREACHABLE! > { "changed": false, "msg": "Failed to connect to the host via ssh: Perm…...
有限元中三角形的一些积分公式
文章目录有限元中三角形的相关积分公式有限元中三角形的相关积分公式 在 xyxyxy 平面中, 通过三个点 (xi,yi),(xj,yj),(xm,ym)(x_i, y_i), (x_j, y_j), (x_m, y_m)(xi,yi),(xj,yj),(xm,ym) 定义一个三角形, 令坐标原点位于其中心(或者重心)…...
【docker-compose】安装mongodb
1. 安装方式 压缩包容器安装docker(推荐,一分钟安装) 2. 环境 linux服务器已安装好 docker docker-compose (不了解的客官,请点击进入) 3. 步骤: Step 1: linux下建立如下目录…...
【ClickHouse源码】物化视图的写入过程
本文对 ClickHouse 物化视图的写入流程源码做个详细说明,基于 v22.8.14.53-lts 版本。 StorageMaterializedView 首先来看物化视图的构造函数: StorageMaterializedView::StorageMaterializedView(const StorageID & table_id_,ContextPtr local_…...

.NET 使用NLog增强日志输出
引言 不管你是开发单体应用还是微服务应用,在实际的软件的开发、测试和运行阶段,开发者都需要借助日志来定位问题。因此一款好的日志组件将至关重要,在.NET 的开源生态中,目前主要有Serilog、Log4Net和NLog三款优秀的日志组件&…...

一道阿里类的初始化顺序笔试题
问题很简单,就是下面的代码打印出什么? public class InitializeDemo {private static int k 1;private static InitializeDemo t1 new InitializeDemo("t1" );private static InitializeDemo t2 new InitializeDemo("t2");priv…...
cuda找不到路径报错
编译C文件时出现:error: [Errno 2] No such file or directory: :/usr/local/cuda:/usr/local/cuda/bin/nvcc 在终端输入: export CUDA_HOME/usr/local/cuda...

【人工智能】神经网络的优化器optimizer(二):Adagrad自适应学习率优化器
一.自适应梯度算法Adagrad概述 Adagrad(Adaptive Gradient Algorithm)是一种自适应学习率的优化算法,由Duchi等人在2011年提出。其核心思想是针对不同参数自动调整学习率,适合处理稀疏数据和不同参数梯度差异较大的场景。Adagrad通…...
Golang dig框架与GraphQL的完美结合
将 Go 的 Dig 依赖注入框架与 GraphQL 结合使用,可以显著提升应用程序的可维护性、可测试性以及灵活性。 Dig 是一个强大的依赖注入容器,能够帮助开发者更好地管理复杂的依赖关系,而 GraphQL 则是一种用于 API 的查询语言,能够提…...

【CSS position 属性】static、relative、fixed、absolute 、sticky详细介绍,多层嵌套定位示例
文章目录 ★ position 的五种类型及基本用法 ★ 一、position 属性概述 二、position 的五种类型详解(初学者版) 1. static(默认值) 2. relative(相对定位) 3. absolute(绝对定位) 4. fixed(固定定位) 5. sticky(粘性定位) 三、定位元素的层级关系(z-i…...

Java-41 深入浅出 Spring - 声明式事务的支持 事务配置 XML模式 XML+注解模式
点一下关注吧!!!非常感谢!!持续更新!!! 🚀 AI篇持续更新中!(长期更新) 目前2025年06月05日更新到: AI炼丹日志-28 - Aud…...

【Zephyr 系列 10】实战项目:打造一个蓝牙传感器终端 + 网关系统(完整架构与全栈实现)
🧠关键词:Zephyr、BLE、终端、网关、广播、连接、传感器、数据采集、低功耗、系统集成 📌目标读者:希望基于 Zephyr 构建 BLE 系统架构、实现终端与网关协作、具备产品交付能力的开发者 📊篇幅字数:约 5200 字 ✨ 项目总览 在物联网实际项目中,**“终端 + 网关”**是…...
LLM基础1_语言模型如何处理文本
基于GitHub项目:https://github.com/datawhalechina/llms-from-scratch-cn 工具介绍 tiktoken:OpenAI开发的专业"分词器" torch:Facebook开发的强力计算引擎,相当于超级计算器 理解词嵌入:给词语画"…...

UR 协作机器人「三剑客」:精密轻量担当(UR7e)、全能协作主力(UR12e)、重型任务专家(UR15)
UR协作机器人正以其卓越性能在现代制造业自动化中扮演重要角色。UR7e、UR12e和UR15通过创新技术和精准设计满足了不同行业的多样化需求。其中,UR15以其速度、精度及人工智能准备能力成为自动化领域的重要突破。UR7e和UR12e则在负载规格和市场定位上不断优化…...
LeetCode - 199. 二叉树的右视图
题目 199. 二叉树的右视图 - 力扣(LeetCode) 思路 右视图是指从树的右侧看,对于每一层,只能看到该层最右边的节点。实现思路是: 使用深度优先搜索(DFS)按照"根-右-左"的顺序遍历树记录每个节点的深度对于…...

【分享】推荐一些办公小工具
1、PDF 在线转换 https://smallpdf.com/cn/pdf-tools 推荐理由:大部分的转换软件需要收费,要么功能不齐全,而开会员又用不了几次浪费钱,借用别人的又不安全。 这个网站它不需要登录或下载安装。而且提供的免费功能就能满足日常…...
【SSH疑难排查】轻松解决新版OpenSSH连接旧服务器的“no matching...“系列算法协商失败问题
【SSH疑难排查】轻松解决新版OpenSSH连接旧服务器的"no matching..."系列算法协商失败问题 摘要: 近期,在使用较新版本的OpenSSH客户端连接老旧SSH服务器时,会遇到 "no matching key exchange method found", "n…...