分类目录归档:技术笔记

Docker 官方脚本一键安装

使用官方脚本安装

curl -fsSL https://get.docker.com | bash -s docker --mirror Aliyun

curl -fsSL https://res.frytea.com/d/Dev/Docker/get_docker.sh | bash -s docker --mirror Aliyun

curl -fsSL https://res.frytea.com/d/Dev/Docker/get_docker.sh | DOWNLOAD_URL=http://192.168.25.10/docker  bash -s docker

# ustc
curl -fsSL https://get.docker.com -o get-docker.sh
sudo DOWNLOAD_URL=https://mirrors.ustc.edu.cn/docker-ce sh get-docker.sh

# 也可以自己在内网做一个镜像,将脚本和 docker 软件源全部镜像,可以实现全内网高速安装
curl -fsSL http://192.168.25.9/raw/general/docker/install-docker.sh -o get-docker.sh
sudo DOWNLOAD_URL=http://192.168.25.10/docker sh get-docker.sh

curl -fsSL http://192.168.25.9/raw/general/docker/install-docker.sh |  DOWNLOAD_URL=http://192.168.25.10/docker bash -s

安装完成后使能 docker 服务:

systemctl enable docker
syste sart docker
sudo usermod -aG docker $USER

参考文献

#Docker

s3cmd 常见用法

常见用法

  • 列举所有 Buckets
    $ s3cmd ls
  • 创建 bucket,且 bucket 名称是唯一的,不能重复。
    s3cmd mb s3://my-bucket-name
  • 删除空 bucket
    s3cmd rb s3://my-bucket-name
  • 列举 Bucket 中的内容
    s3cmd ls s3://my-bucket-name
  • 上传 file.txt 到某个 bucket,
    s3cmd put file.txt s3://my-bucket-name/file.txt
  • 上传并将权限设置为所有人可读
    s3cmd put --acl-public file.txt s3://my-bucket-name/file.txt
  • 批量上传文件
    s3cmd put ./* s3://my-bucket-name/
  • 下载文件
    s3cmd get s3://my-bucket-name/file.txt file.txt
  • 批量下载
    s3cmd get s3://my-bucket-name/* ./
  • 删除文件
    s3cmd del s3://my-bucket-name/file.txt
  • 来获得对应的bucket所占用的空间大小
    s3cmd du -H s3://my-bucket-name
  • 设置S3 bucket的Public权限
    s3cmd setacl s3://myexamplebucket.calvium.com/ --acl-public --recursive

临时链接

s3cmd signurl s3://example-bucket/image.jpg 1657457538
  • example-bucket — the name of the bucket that hosts the file,
  • image.jpg — the file you want to share,
  • 1657457538 — link expiry time in the Timestamp format, use the converter to convert time formats.

References

Rails 7 已有项目引入 Bootstrap 3

若是新项目,在 Rails 7 之后直接使用 rails new test -j esbuild --css bootstrap 即可,若是已有项目,使用下面步骤引入:

主要步骤

安装 cssbundling-rails 管理 CSS

bundle add cssbundling-rails
./bin/rails css:install:bootstrap

做了以下几件事情:

  • 它会创建 builds 文件夹,并在清单文件中链接它
  • 它会删除 application.css 文件,因为它会生成自己的文件。
  • 它添加了一个 package.json 文件来存储 Javascript 依赖项。
  • 它会安装 foreman gem,并为其生成一个配置文件。
  • 它添加了一个 bin/dev 脚本来启动 rails 服务器,并监视 CSS 文件的任何更改。
  • 它会创建特定于 Bootstrap 的 scss 文件,该文件将被捆绑到一个 application.css 文件中。
  • 它将安装 package.json 文件中列出的所有 Javascript 依赖项。
  • 它将 Bootstrap 字体路径附加到 assets 路径。
  • 它将 Bootstrap Javascript 导入添加到 application.js 文件中。
  • 最后,它配置 build:css 命令并运行它来构建 application.css 文件。

安装 jsbundling-rails 处理 JS 绑定

bundle add jsbundling-rails
./bin/rails javascript:install:esbuild

上述脚本做了这些事情:

  • 它会检查 builds 文件夹,但因为我们已经有了它,所以它不会做任何事情。
  • 它将 javascript_include_tag 添加到应用程序布局文件中。
  • 它在 foreman 配置文件中添加一个任务,以监视任何 Javascript 更改。
  • 它安装 esbuild 打包器,并尝试构建 Javascript 代码。

疑难问题

$ esbuild app/javascript/*.* --bundle --sourcemap --outdir=app/assets/builds --public-path=assets
✘ [ERROR] Could not resolve "controllers"

    app/javascript/application.js:3:7:
      3 │ import "controllers"
        │        ~~~~~~~~~~~~~
        ╵        "./controllers"

  Use the relative path "./controllers" to reference the file "app/javascript/controllers/index.js".
  Without the leading "./", the path "controllers" is being interpreted as a package path instead.

1 error
node:child_process:866
    throw err;
    ^

Error: Command failed: /Users/cezar/Work/ror/bootstrap/node_modules/esbuild-darwin-arm64/bin/esbuild app/javascript/application.js --bundle --sourcemap --outdir=app/assets/builds --public-path=assets
    at checkExecSyncError (node:child_process:828:11)
    at Object.execFileSync (node:child_process:863:15)
    at Object.
<anonymous> (/Users/cezar/Work/ror/bootstrap/node_modules/esbuild/bin/esbuild:209:28)
    at Module._compile (node:internal/modules/cjs/loader:1099:14)
    at Object.Module._extensions..js (node:internal/modules/cjs/loader:1153:10)
    at Module.load (node:internal/modules/cjs/loader:975:32)
    at Function.Module._load (node:internal/modules/cjs/loader:822:12)
    at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:77:12)
    at node:internal/main/run_main_module:17:47 {
  status: 1,
  signal: null,
  output: [ null, null, null ],
  pid: 94418,
  stdout: null,
  stderr: null
}

Node.js v17.8.0
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.

因为我们有一些 import maps 留下的代码,这与 jsbundling-rails gem 的工作方式相冲突。

因此,让我们解决这些问题。

修复安装

首先要做的是安装 turbo-railsstimulus 包。

yarn add @hotwired/turbo-rails
yarn add @hotwired/stimulus

然后,我将调整 application.js 文件中的导入路径,并删除旧的刺激导入。

--- a/app/javascript/application.js
+++ b/app/javascript/application.js
-import "controllers"
+import "./controllers";

--- a/app/javascript/controllers/index.js
+++ b/app/javascript/controllers/index.js
-import { application } from "controllers/application"
-
-// Eager load all controllers defined in the import map under controllers/**/*_controller
-import { eagerLoadControllersFrom } from "@hotwired/stimulus-loading"
-eagerLoadControllersFrom("controllers", application)
-
-// Lazy load controllers as they appear in the DOM (remember not to preload controllers in import map!)
-// import { lazyLoadControllersFrom } from "@hotwired/stimulus-loading"
-// lazyLoadControllersFrom("controllers", application)
+import { application } from "./application";

在应用程序布局文件中,我将删除 javascript_importmap_tags 帮助程序,因为它不再需要。

--- a/app/views/layouts/application.html.erb
+++ b/app/views/layouts/application.html.erb
     <%= stylesheet_link_tag "application", "data-turbo-track": "reload" %>
-    <%= javascript_importmap_tags %>
     <%= javascript_include_tag "application", "data-turbo-track": "reload", defer: true %>
   </head>

最后,我将取消链接其他 javascript 文件夹,只在清单中留下 builds 文件夹和 images 文件夹。

--- a/app/assets/config/manifest.js
+++ b/app/assets/config/manifest.js
 //= link_tree ../images
-//= link_tree ../../javascript .js
-//= link_tree ../../../vendor/javascript .js
 //= link_tree ../builds

安装 Bootstrap3

以上命令默认会安装最新的 Bootstrap, 如果像我一样需要安装旧版本,则按照以下步骤:

首先安装 Bootstrap 3jquery

yarn add bootstrap@3
yarn add jquery

之后创建一个 js 文件 app/javascript/add_jquery.js :

import jquery from 'jquery'
window.jQuery = jquery
window.$ = jquery

最后在 app/javascript/application.js 中引入即可:

...
import './add_jquery'  

import "jquery/dist/jquery"  
import "bootstrap/dist/js/bootstrap"
...

css 则是在 app/assets/stylesheets/application.bootstrap.scss 中写入:

+ @import 'bootstrap/dist/css/bootstrap';
@import 'bootstrap-icons/font/bootstrap-icons';

链接 debugger

以上操作后就可以使用 bin/dev 启动项目,会自动起来三个服务,这时如果使用 debugger 启动调试,就可以使用以下命令链接:

rdbg --attach

References

Ruby 多版本管理工具 rbenv

rbenv (Simple Ruby Version Management) 允许您在 Ruby 的多个版本之间轻松切换。它简单、不引人注目,并遵循 UNIX 的传统,即只做一件事的单一用途工具。

安装方法

安装 rbenv

# Archlinux
sudo pacman -S rbenv
# macOS
brew install rbenv
# Debian/Ubuntu
sudo apt install rbenv
# Fedora/RHEL
sudo dnf install rbenv

安装 ruby-build

使用 rbenv 安装 ruby 版本需要用到 install 命令,但是该 rbenv install 命令不是开箱即用的 rbenv 提供的,而是由 ruby-build 插件提供的,下面一同安装:

# Archlinux
sudo pacman -S ruby-build
# macOS
brew install ruby-build

使用方法

# 首先初始化
rbenv init

# 查看可安装版本
rbenv install -l # list latest stable versions
rbenv install -L # list all local versions

# 安装某个版本
rbenv install 3.1.2

# 使用某个版本
rbenv global 3.1.2 # set the default Ruby version for this machine
rbenv local 3.1.2  # set the Ruby version for this directory

References

使用 GCOP AI 助力提升 git commit 效率

最近在 阮老师博客 看到一款这个 GCOP,一个基于 LLM 的 Git 提交消息生成和 Git 工作流程优化工具,试用了一下确实不错。接入 LLM 即可自动分析 git 修改生成 commit 消息,比我之前做的 git-commit 生成器好用多了。

以下是一些简单介绍:

简介

GCOP (Git Copilot) 是一个 Git 智能助手,它使用 AI 来自动生成 Git 提交消息,帮助开发者优化 Git 工作流程。

主要功能

  1. 智能提交消息:自动分析代码变更,生成高质量、定制化的提交消息,并提供多种细粒度配置,确保团队提交标准的一致性
  2. 灵活的 AI 集成:支持配置各种 LLM 模型(如 OpenAI GPT、Claude、Deepseek 等)
  3. 简化的 Git 命令:内置 20+ 直观的 Git 快捷操作和命令,提供直观的命令别名,如 git c 用于 AI 辅助提交,优化 Git 工作流程
  4. 无缝工作流集成:增强现有 Git 工作流程,无需改变使用习惯

优点

🎨 高度可定制化体验

  • 提供全局配置和项目级配置,配置项目特定设置,确保团队标准的一致性
  • 设计专属提交模板以匹配项目需求
  • 通过自定义提示优化 git message 的风格

⚡ 流畅的开发者体验

  • 内置 20+ 直观的 Git 快捷操作和命令,智能别名让复杂的 Git 操作轻而易举
  • 支持各种 LLM 模型(OpenAI、Anthropic、Deepseek 等)
  • 零配置集成至现有的 Git 工作流

📚 智能学习能力

  • 自动学习您的代码库提交历史
  • 随时间适应团队的提交习惯
  • 通过持续学习提升信息质量

项目完全开源,使用 MIT 协议,基于 Python 开发。

Github: https://github.com/Undertone0809/gcop
官网: https://gcop.zeeland.top/

使用方法

安装配置参考官网 Quick Start Guide 即可,mac 下可以结合 conda 安装,之后大概按照这样配置:

model:
  model_name: openai/gpt-4o-mini
  api_key: sk-xxxx
  api_base: https://api.xxx.io/v1

即可使用。

效果

(base) songtianlun@songtianlundeMacBook-Air sample_rails_app % git ac
[Code diff] 
diff --git a/.gitignore b/.gitignore
index afd85fd..daa7023 100644
--- a/.gitignore
+++ b/.gitignore
@@ -37,3 +37,5 @@
 !/app/assets/builds/.keep

 /node_modules
+
+.idea
[On Ready] Generating commit message...
[Thought] The changes involve the removal of several .idea configuration files and the 
addition of .idea to the .gitignore file. This indicates a cleanup of IDE-specific files 
that are not necessary for version control, which can help reduce clutter in the repository.
[Generated commit message]
chore: remove IDE configuration files

- Deleted .idea/misc.xml, .idea/modules.xml, and .idea/sample_rails_app.iml files
- Added .idea to .gitignore to prevent future IDE files from being tracked

This commit cleans up the repository by removing IDE-specific configuration files that are 
not needed for the project. It also ensures that any future IDE files will be ignored, 
keeping the repository clean and focused on the actual project code.
? Do you want to commit the changes with this message? yes
[main d86005c] chore: remove IDE configuration files
 6 files changed, 2 insertions(+), 373 deletions(-)
 delete mode 100644 .idea/.gitignore
 delete mode 100644 .idea/misc.xml
 delete mode 100644 .idea/modules.xml
 delete mode 100644 .idea/sample_rails_app.iml
 delete mode 100644 .idea/vcs.xml
(base) songtianlun@songtianlundeMacBook-Air sample_rails_app % git push

常用命令

$ git ghelp                
/opt/homebrew/Caskroom/miniconda/base/lib/python3.12/site-packages/pydantic/_internal/_config.py:345: UserWarning: Valid config keys have changed in V2:
* 'fields' has been removed
  warnings.warn(message, UserWarning)

gcop is your local git command copilot
Version: 1.7.3
GitHub: https://github.com/Undertone0809/gcop

Usage: gcop [OPTIONS] COMMAND

Commands:
  git p          Push the changes to the remote repository
  git pf         Push the changes to the remote repository with force
  git undo       Undo the last commit but keep the file changes
  git ghelp      Add command into git config
  git gconfig    Open the config file in the default editor
  git gcommit    Generate a git commit message based on the staged changes and commit the 
changes
  git c          The same as `git gcommit` command
  git ac         The same as `git add . && git gcommit` command
  git acp        The same as `git add . && git gcommit && git push` command
  git cp         The same as `git gcommit && git push` command
  git amend      Amend the last commit, allowing you to modify the commit message or add 
changes to the previous commit
  git info       Display basic information about the current git repository

改好代码之后 git ac && git push 两行命令搞定标准格式提交,很方便。

References

Linux buffer-cache 占用过高性能调整

什么是 buff/cache?

Linux 2.4 的内存管理中,buffer 指 Linux 内存的:Buffer cachecache 指 Linux 内存中的:Page cache。一般呢,是这么解释两者的。

  • A buffer is someting that has yet to be ‘written’ to disk.
  • A cache is someting that has been ‘read’ from the disk and stored for later use.

翻译过来就是说:

  1. buffer (buff) 是用来缓存尚未 “写入” 磁盘的内容。
  2. cache 是用来缓存从磁盘 “读取” 出来的东西。

所以 buffer 被用来当成对 io 设备写的缓存。而 cache 被用来当作对 io 设备的读缓存。这里的 io 设备,主要指的是块设备文件和文件系统上的普通文件。

但是在 Linux 2.6 以后,它们的意义不一样了。

Linux 2.6 之后 Linux 将他们统一合并到了 Page cache 作为文件层的缓存。而 buffer 则被用作 block 层的缓存。
block 层的缓存是什么意思呢,你可以认为一个 buffer 是一个 physical disk block 在内存的代表,用来将内存中的 pages 映射为 disk blocks,这部分被使用的内存被叫做 buffer

buffer 里面的 pages,指的是 Page cache 中的 pages,所以,buffer 也可以被认为 Page cache 的一部分。

或者简单来说,buffer 负责裸设备相关的缓存,cache 负责文件系统的缓存。

Buffer 的具体职责

在当前的系统实现里,buffer 主要是设计用来在系统对块设备进行读写时作为缓存来使用。这意味着对块的操作会使用 buffer 进行缓存,比如我们在格式化文件系统的时候。

但是一般情况下两个缓存系统是一起配合使用的,比如当我们对一个文件进行写操作的时候,cache 的内容会被改变,而 buffer 则用来将 cachepage 标记为不同的缓冲区,并记录是哪一个缓冲区被修改了。

这样,内核在后续执行脏数据的回写(writeback)时,就不用将整个 page 写回,而只需要写回修改的部分即可。

Cache 的具体职责

cache 主要用来作为文件系统上的文件数据的缓存来用,当进程对文件有 read/write 操作的时候。包括将文件映射到内存的系统调用 mmap,就会用到 cache

因为 cache 被作为文件类型的缓存来用,所以事实上也负责了大部分的块设备文件的缓存工作。

怎么回收 buff/cache?

Linux 内核会在内存将要耗尽的时候,自动触发内存回收的工作,以便释放出内存给急需内存的进程使用。

但是这种回收的工作也并不是没有成本。

理解 cache 是干什么的就知道,cache 中存在着一部分 write 操作的数据。所以必须保证 cache 中的数据跟对应文件中的数据一致,才能对 cache 进行释放。

于是伴随着 cache 清除的行为的,一般都是系统 IO 飙高。这是因为内核要将 cache 中缓存的 write 数据进行回写。

我们可以使用下面这个文件来人工触发缓存清除的操作,Linux 提供了三种清空方式:

  1. echo 1 > /proc/sys/vm/drop_caches # 仅清除页面缓存
  2. echo 2 > /proc/sys/vm/drop_caches # 清除目录项和 inode
  3. echo 3 > /proc/sys/vm/drop_caches # 清除页面缓存、目录项以及 inode

但是这种放时只能在执行的当时起作用,过一段时间之后又会发现内存被占满,怎么办呢?

实际上内核提供了 vm.vfs_cache_pressure 参数用来控制缓冲区的回收频率,我们可以调整它。

这个参数是用来控制内核回收 VFS 缓存的频率。修改这个值会提高或者降低回收 VFS 缓存的频率。值可以设置为 0-200 中的任意值。越大回收频率越快,可以把 vm.vfs_cache_pressure 赋值为 200 来获得最快的回收频率。这个值默认值一般为 100

另外也可以使用 slabtop 分析内存使用情况。一般情况下,dentry*_inode_cache 值越高回收的效果越好。

为什么是 dentry*_inode_cache 呢,这是因为当读写文件时内核会为该文件对象建立一个 dentry,并将其缓存起来,方便下一次读写时直接从内存中取出提高效率。

一些措施

内核参数

可以通过配置 vm.vfs_cache_pressure 参数,控制系统回收 directory entries 和 inode 缓存的倾向程度

Linux Kernel 文档描述如下:

此百分比值控制内核回收用于缓存 directoryinode 对象的内存的趋势。 在默认值 vfs_cache_pressure=100 时,内核将尝试以 pagecacheswapcache 回收的“公平”速率回收 dentryinode。减小 vfs_cache_pressure 会导致内核更倾向于保留 dentryinode 缓存。当 vfs_cache_pressure=0 时,由于内存压力,内核永远不会回收 dentryinode,这很容易导致内存不足的情况。将 vfs_cache_pressure 增加到 100 以上会导致内核更喜欢回收 dentryinode。 将 vfs_cache_pressure 显著增加到 100 以上可能会对性能产生负面影响。回收代码需要使用各种锁来查找可释放的目录和 inode 对象。当 vfs_cache_pressure=1000 时,它将查找比可用对象多 10 倍的可用对象。

可尝试将该值调整为 200 使得比默认值更积极地回收缓存,要持久化配置 vm.vfs_cache_pressure 为 200你可以通过以下几种方法:

  1. 通过 /etc/sysctl.conf 文件(推荐方法):
# 使用文本编辑器打开 /etc/sysctl.conf
sudo vim /etc/sysctl.conf

# 添加或修改以下行
vm.vfs_cache_pressure = 200

# 使配置生效
sudo sysctl -p
  1. 通过创建 /etc/sysctl.d/ 目录下的配置文件:
# 创建新的配置文件
sudo vim /etc/sysctl.d/99-vfs-cache-pressure.conf

# 添加以下行
vm.vfs_cache_pressure = 200

# 使配置生效
sudo sysctl --system

手动清理

$ sync
$ echo 1 > /proc/sys/vm/drop_caches
$ echo 2 > /proc/sys/vm/drop_caches
$ echo 3 > /proc/sys/vm/drop_caches

自动定时清理

不推荐这么做

1、创建脚本cleanCache.sh

#!/bin/bash#每两小时清除一次缓存
echo "开始清除缓存"
sync;sync;sync #写入硬盘,防止数据丢失
sleep 10#延迟10秒
echo 1 > /proc/sys/vm/drop_caches
echo 2 > /proc/sys/vm/drop_caches
echo 3 > /proc/sys/vm/drop_caches

2、创建定时任务

crontab -e #弹出配置文件

3、添加定时任务执行频率

#分  时  日  月  周  命令
0 */2 * * * /usr/local/bin/cleanCache.sh

4、设置crond启动以及开机自启

systemctl start crond.service
systemctl enable crond.service

5、查看定时任务是否被执行

cat /var/log/cron | grep cleanCache

References

VirtualBox VERR_NO_LOW_MEMORY 解决

Archlinux 下内存有很多,但 VB 报错内存不足 VM 无法启动,free 可以看到内存大部分被 buffer 占用。

free -h
              total        used        free      shared  buff/cache   available  
内存:          30Gi        13Gi        1Gi       2.3Gi       18.7Gi        17Gi  
交换:          31Gi       1.7Gi        30Gi

论坛找到一种强制驱逐 buffer 占用的方法:

echo 3 > /proc/sys/vm/drop_caches

执行后可正常启动。

References

GitHub 个人仓库批量备份到自建 Gitea

这是一个自动将 GitHub 仓库镜像到 Gitea 的 Shell 脚本。支持批量同步所有仓库,可以设置跳过特定仓库,并具有良好的错误处理机制。

由于 GitHub 仓库较多,因为各种原因担心数据风险和访问困难。代码托管在自建 gitea 虽然访问快,但是脱离了生态很难跟其他的 PaaS 平台对接。

于是就编写了一套脚本,这套脚本从 Github api 获取 repo 清单,逐个 mirror 后推送到 gitea,最后收集同步报告发送邮件通知。结合 crontab 可实现自动化的 git repo 同步备份。

花了一点时间来写,干脆分享出来,可以i根据自己的需求定制。

邮件效果:

邮件截图

运行效果:

运行截图

支持 helm 的 harbor 版本

Harbor在v1.6版本开始支持Helm Chart仓库功能,- 从v2.6.0 开始弃用Chartmuseum,并在v2.8.0中开始删除。更多详情,请参阅讨论:https://github.com/goharbor/harbor/discussions/15057 从 v2.6.0 开始弃用 Notary(签名者和服务器),并在 v2.8.0 中开始删除。更多详情,请参阅讨论:https://github.com/goharbor/harbor/discussions/16612

安装Chartmuseum组件

修改配置文件

  在absolute_url​参使用ChartMuseum​组件时,客户端获取到的Chart的index.yaml​中包含的URL是否为绝对路径。在不配置该项时,ChartMuseum组件会返回相对路径,默认为disabled。

$ vim  harbor.yml
chart:
  # Change the value of absolute_url to enabled can enable absolute url in chart
  absolute_url: enabled

enabled表示使用绝对路径!

停止Harbor

$ docker-compose stop

注入配置

  执行./prepare将新的配置注入到各个组件中。

$  ./prepare

安装chartmuseum

  在执行install.sh安装时,通过–with-chartmuseum参数安装chart插件,安装完后会自动启动Harbor。

$ ./install.sh  --with-notary --with-trivy --with-chartmuseum
✔ ----Harbor has been installed and started successfully.----  #输出该信息则表示安装成功

查看组件服务状态

  通过docker-compose ps命令可以看到harbor的组件中多了个chartmuseum的容器。

$ docker-compose ps

验证是否安装了chartmuseum组件

登录Harbor UI管理界面:【项目】==>【library】==> 【Helm Charts】

References

#Harbor #Docker

配置 harbor 及 docker 等使用 https

默认情况下,Harbor不提供证书。可以在没有安全性的情况下部署Harbor,这样您就可以通过HTTP连接到它。但是,只有在没有连接到外部internet的空间隙测试或开发环境中才可以使用HTTP。在没有空间隙的环境中使用HTTP会暴露给中间人攻击。在生产环境中,始终使用HTTPS。如果启用带公证人的内容信任对所有images进行正确签名,则必须使用HTTPS。

要配置HTTPS,必须创建SSL证书。您可以使用由受信任的第三方CA签名的证书,也可以使用自签名证书。本节介绍如何使用OpenSSL创建CA,以及如何使用CA签署服务器证书和客户端证书。您可以使用其他CA提供程序,例如:Let’s Encrypt。

下面的过程假设您的Harbor注册表的主机名是 yourdomain.com,并且它的DNS记录指向运行Harbor的主机。

生成证书颁发机构的证书

在生产环境中,应该从CA获取证书。在测试或开发环境中,可以生成自己的CA。若要生成CA证书,请运行以下命令。

生成CA证书私钥。

openssl genrsa -out ca.key 4096

生成CA证书。 

调整 -subj选项中的值以反映您的组织。如果使用 FQDN 连接Harbor主机,则必须将其指定为 common name(CN)属性。

公用名(Common Name)一般来讲就是填写你将要申请SSL证书的域名 (domain)或子域名(sub domain)。

例1:打算为“chinassl.net”申请SSL证 书,那这个公用名(Common Name)就要填写“chinassl.net”,而不能填写 “www.chinassl.net”,因为在申请SSL证书时发证机构认为“www.yourdomain.com”和 “yourdomain.com”是不同的两个域名;

例2:如将要为bill.chinassl.net申请SSL证书,那么这里公用名(Common Name)就 要填写“bill.chinassl.net”而不能填写“chinassl.net”或“www.chinassl.net”
openssl req -x509 -new -nodes -sha512 -days 3650 \
 -subj "/C=CN/ST=Beijing/L=Beijing/O=example/OU=Personal/CN=yourdomain.com" \
 -key ca.key \
 -out ca.crt

生成服务器证书

证书通常包含.crt文件和.key文件,例如yourdomain.com.crt和yourdomain.com.key。

1、生成私钥。

openssl genrsa -out yourdomain.com.key 4096

 2、生成证书签名请求(CSR)。

调整-subj选项中的值以反映您的组织。如果使用FQDN连接Harbor主机,则必须将其指定为common name(CN)属性,并在key和CSR文件名中使用它。

openssl req -sha512 -new \
    -subj "/C=CN/ST=Beijing/L=Beijing/O=example/OU=Personal/CN=yourdomain.com" \
    -key yourdomain.com.key \
    -out yourdomain.com.csr

 3、生成 x509 v3 扩展文件。

无论您是使用 FQDN 还是使用IP地址连接到您的 Harbor 主机,都必须创建此文件,以便您可以为 Harbor 主机生成符合使用者替代名称(SAN)和 x509 v3 扩展要求的证书。替换DNS条目以反映您的域。

cat > v3.ext <<-EOF
authorityKeyIdentifier=keyid,issuer
basicConstraints=CA:FALSE
keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment
extendedKeyUsage = serverAuth
subjectAltName = @alt_names

[alt_names]
DNS.1=yourdomain.com
DNS.2=yourdomain
DNS.3=hostname
IP.1 = 192.168.25.8
EOF

 4、使用 v3.ext 文件为您的港口主机生成证书。

CRSCRT 文件名中的 yourdomain.com 替换为 Harbor 主机名。

openssl x509 -req -sha512 -days 3650 \
    -extfile v3.ext \
    -CA ca.crt -CAkey ca.key -CAcreateserial \
    -in yourdomain.com.csr \
    -out yourdomain.com.crt

向 Harbor 和 Docker 提供证书

生成 ca.crtyourdomain.com.crtyourdomain.com.key 文件后,必须将它们提供给Harbor和Docker,并重新配置Harbor以使用它们。

1、将服务器证书和密钥复制到Harbor主机上的 certcificates 文件夹中。

cp yourdomain.com.crt /data/cert/
cp yourdomain.com.key /data/cert/

 2、将 yourdomain.com.crt 转换为 yourdomain.com.cert ,供Docker使用。

Docker守护进程将 .crt 文件解释为 CA 证书,.cert文件解释为客户端证书。

openssl x509 -inform PEM -in yourdomain.com.crt -out yourdomain.com.cert

 3、将服务器证书、密钥和CA文件复制到港口主机上的Docker certificates文件夹中。必须先创建适当的文件夹。

cp yourdomain.com.cert /etc/docker/certs.d/yourdomain.com/
cp yourdomain.com.key /etc/docker/certs.d/yourdomain.com/
cp ca.crt /etc/docker/certs.d/yourdomain.com/

 如果将默认nginx端口443映射到其他端口,请创建文件夹 /etc/docker/certs.d/yourdomain.com:port/etc/docker/certs.d/harbor_IP:port

4、重新启动Docker引擎。

systemctl restart docker

您可能还需要在操作系统级别信任证书。有关详细信息,请参阅harbor安装疑难解答

下面的示例演示了使用自定义证书的配置。

/etc/docker/certs.d/
    └── yourdomain.com:port
       ├── yourdomain.com.cert  <-- Server certificate signed by CA
       ├── yourdomain.com.key   <-- Server key signed by CA
       └── ca.crt               <-- Certificate authority that signed the registry certificate

部署或重新配置harbor

如果尚未部署Harbor,请参阅配置Harbor YML文件,以获取有关如何通过在Harbor.YML中指定主机名和https属性来配置Harbor以使用证书的信息。

如果您已经使用HTTP部署了Harbor并希望将其重新配置为使用HTTPS,请执行以下步骤。

1、运行prepare脚本以启用HTTPS。

Harbor使用nginx实例作为所有服务的反向代理。使用prepare脚本将nginx配置为使用HTTPS。prepare 位于Harbor安装包中,与 install.sh 脚本处于同一级别。

./prepare

2、如果Harbor正在运行,请停止并删除现有实例。

images数据保留在文件系统中,因此不会丢失任何数据。

docker-compose down -v

3、Restart Harbor:

docker-compose up -d

验证HTTPS连接

在为Harbor设置HTTPS之后,您可以通过执行以下步骤来验证HTTPS连接。

1、打开浏览器并输入 https://yourdomain.com。它应该显示 harbor 界面。

某些浏览器可能会显示一条警告,指出证书颁发机构(CA)未知。使用非来自可信第三方 CA 的自签名 CA 时会发生这种情况。您可以将 CA 导入浏览器以删除警告。

2、在运行Docker守护进程的计算机上,检查 `文件,确保没有为https://yourdomain.com设置-unsecure-registry` 选项。

3、从Docker客户端登录到Harbor。

docker login yourdomain.com

 如果您已经将nginx 443端口映射到另一个端口,请在login命令中添加该端口。

docker login yourdomain.com:port

其他工具接入

Docker

cp yourdomain.com.cert /etc/docker/certs.d/yourdomain.com/
cp yourdomain.com.key /etc/docker/certs.d/yourdomain.com/
cp ca.crt /etc/docker/certs.d/yourdomain.com/

cp x.x.x.x:xxx.cert /etc/docker/certs.d/x.x.x.x:xxx/
cp x.x.x.x:xxx.key /etc/docker/certs.d/x.x.x.x:xxx/
cp ca.crt /etc/docker/certs.d/x.x.x.x:xxx/

Containerd

cp yourdomain.com.cert /etc/containerd/certs.d/yourdomain.com/
cp yourdomain.com.key /etc/containerd/certs.d/yourdomain.com/
cp ca.crt /etc/containerd/certs.d/yourdomain.com/

cp x.x.x.x:xxx.cert /etc/containerd/certs.d/x.x.x.x:xxx/
cp x.x.x.x:xxx.key /etc/containerd/certs.d/x.x.x.x:xxx/
cp ca.crt /etc/containerd/certs.d/x.x.x.x:xxx/

# example
mkdir -p /etc/containerd/certs.d/192.168.25.8:10443
cd /etc/containerd/certs.d/192.168.25.8:10443
wget http://192.168.25.9/raw/general/wz_harbor_ssl/192.168.25.8%3A10443.cert
wget http://192.168.25.9/raw/general/wz_harbor_ssl/192.168.25.8%3A10443.key
wget http://192.168.25.9/raw/general/wz_harbor_ssl/ca.crt
systemctl restart containerd.servic

skopeo

直接支持 /etc/docker/certs.d/ 目录下的证书。

helm

References