chore(All Markdown Files): auto wrap text, fix typos

This commit is contained in:
Ryan Yin
2024-03-16 19:45:36 +08:00
parent 1e38f7bb09
commit 0eb83b22f0
79 changed files with 2477 additions and 2896 deletions

2
.github/FUNDING.yml vendored
View File

@@ -1,2 +1,2 @@
patreon: ryan4yin
custom: ['https://buymeacoffee.com/ryan4yin', 'https://afdian.net/a/ryan4yin']
custom: ["https://buymeacoffee.com/ryan4yin", "https://afdian.net/a/ryan4yin"]

View File

@@ -8,7 +8,7 @@ on:
- "scripts/**"
- "**.md"
- "**.nu"
- 'Justfile'
- "Justfile"
pull_request:
branches:
- main
@@ -16,7 +16,7 @@ on:
- "scripts/**"
- "**.md"
- "**.nu"
- 'Justfile'
- "Justfile"
jobs:
checks:

View File

@@ -4,7 +4,7 @@ on:
branches:
- main
tags:
- '*'
- "*"
jobs:
mirror:

View File

@@ -1,5 +1,6 @@
# https://prettier.io/docs/en/options
semi: false
singleQuote: false
printWidth: 80
printWidth: 100
proseWrap: always # always change wrapping in markdown text
trailingComma: es5

12
.typos.toml Normal file
View File

@@ -0,0 +1,12 @@
[files]
ignore-dot = true
ignore-files = true
extend-exclude = ["themes/", "data/", "static-surprises/", "resources/"]
[default]
binary = false
# ignore some special identifiers(sha256, mac address, crypto keys, etc)
extend-ignore-re = [
"iterm2",
"iHgEIBYKACAWIQSizQe9ljFEyyclWmtVhZllwnQrSwUCZZ1T9wIdAAAKCRBVhZll", # crypto keys
]

118
README.md
View File

@@ -14,52 +14,64 @@
</a>
</p>
> My configuration is becoming more and more complex, and it may be difficult for beginners to read it.
> If you are new to NixOS and want to know how I use NixOS, I would recommend you to take a look at the [ryan4yin/nix-config/releases](https://github.com/ryan4yin/nix-config/releases) first, **checkout to some simpler older versions**, which will be much easier to understand.
> My configuration is becoming more and more complex, and it may be difficult for beginners to read
> it. If you are new to NixOS and want to know how I use NixOS, I would recommend you to take a look
> at the [ryan4yin/nix-config/releases](https://github.com/ryan4yin/nix-config/releases) first,
> **checkout to some simpler older versions**, which will be much easier to understand.
This repository is home to the nix code that builds my systems:
1. NixOS Desktops: NixOS with home-manager, i3, hyprland, agenix, etc.
2. macOS Desktops: nix-darwin with home-manager, share the same home-manager configuration with NixOS Desktops.
3. NixOS Servers: virtual machines running on Proxmox, with various services, such as kubernetes, homepage, prometheus, grafana, etc.
2. macOS Desktops: nix-darwin with home-manager, share the same home-manager configuration with
NixOS Desktops.
3. NixOS Servers: virtual machines running on Proxmox, with various services, such as kubernetes,
homepage, prometheus, grafana, etc.
See [./hosts](./hosts) for details of each host.
## Why NixOS & Flakes?
Nix allows for easy-to-manage, collaborative, reproducible deployments. This means that once something is setup and configured once, it works (almost) forever. If someone else shares their configuration, anyone else can just use it (if you really understand what you're copying/refering now).
Nix allows for easy-to-manage, collaborative, reproducible deployments. This means that once
something is setup and configured once, it works (almost) forever. If someone else shares their
configuration, anyone else can just use it (if you really understand what you're copying/refering
now).
As for Flakes, refer to [Introduction to Flakes - NixOS & Nix Flakes Book](https://nixos-and-flakes.thiscute.world/nixos-with-flakes/introduction-to-flakes)
As for Flakes, refer to
[Introduction to Flakes - NixOS & Nix Flakes Book](https://nixos-and-flakes.thiscute.world/nixos-with-flakes/introduction-to-flakes)
**Want to know NixOS & Flaks in detail? Looking for a beginner-friendly tutorial or best practices? You don't have to go through the pain I've experienced again! Check out my [NixOS & Nix Flakes Book - 🛠️ ❤️ An unofficial & opinionated :book: for beginners](https://github.com/ryan4yin/nixos-and-flakes-book)!**
**Want to know NixOS & Flaks in detail? Looking for a beginner-friendly tutorial or best practices?
You don't have to go through the pain I've experienced again! Check out my
[NixOS & Nix Flakes Book - 🛠️ ❤️ An unofficial & opinionated :book: for beginners](https://github.com/ryan4yin/nixos-and-flakes-book)!**
> If you're using macOS, check out [ryan4yin/nix-darwin-kickstarter](https://github.com/ryan4yin/nix-darwin-kickstarter) for a quick start.
> If you're using macOS, check out
> [ryan4yin/nix-darwin-kickstarter](https://github.com/ryan4yin/nix-darwin-kickstarter) for a quick
> start.
## Components
| | NixOS(Wayland) | NixOS(Xorg) |
| --------------------------- | :---------------------------------------------------------------------------------------------------------------- | :---------------------------------------------------------------------------------------------------------------- |
| **Window Manager** | [Hyprland][Hyprland] | [i3][i3] |
| **Terminal Emulator** | [Zellij][Zellij] + [Kitty][Kitty] | [Zellij][Zellij] + [Kitty][Kitty] |
| **Bar** | [Waybar][Waybar] | [polybar][polybar] |
| **Application Launcher** | [anyrun][anyrun] | [rofi][rofi] |
| **Notification Daemon** | [Mako][Mako] | [Dunst][Dunst] |
| **Display Manager** | [GDM][GDM] | [GDM][GDM] |
| **Color Scheme** | [Catppuccin][Catppuccin] | [Catppuccin][Catppuccin] |
| **network management tool** | [NetworkManager][NetworkManager] | [NetworkManager][NetworkManager] |
| **Input method framework** | [Fcitx5][Fcitx5] | [Fcitx5][Fcitx5] |
| **System resource monitor** | [Btop][Btop] | [Btop][Btop] |
| **File Manager** | [Yazi][Yazi] + [thunar][thunar] | [Yazi][Yazi] + [thunar][thunar] |
| **Shell** | [Nushell][Nushell] + [Starship][Starship] | [Nushell][Nushell] + [Starship][Starship] |
| **Music Player** | [mpd][mpd], [ncmpcpp][ncmpcpp], [mpc][mpc], [Netease-cloud-music-gtk][netease-cloud-music-gtk] | [Netease-cloud-music-gtk][netease-cloud-music-gtk] |
| **Media Player** | [mpv][mpv] | [mpv][mpv] |
| **Text Editor** | [Neovim][Neovim] + [DoomEmacs][DoomEmacs] | [Neovim][Neovim] + [DoomEmacs][DoomEmacs] |
| **Fonts** | [Nerd fonts][Nerd fonts] | [Nerd fonts][Nerd fonts] |
| **Image Viewer** | [imv][imv] | [imv][imv] |
| **Screenshot Software** | [flameshot][flameshot] + [grim][grim] | [flameshot][flameshot] |
| **Screen Recording** | [OBS][OBS] | [OBS][OBS] |
| **Filesystem & Encryption** | tmpfs on `/`, [Btrfs][Btrfs] subvolumes on a [LUKS][LUKS] crypted partition for persistent, unlock via passphrase | tmpfs on `/`, [Btrfs][Btrfs] subvolumes on a [LUKS][LUKS] crypted partition for persistent, unlock via passphrase |
| **Secure Boot** | [lanzaboote][lanzaboote] | [lanzaboote][lanzaboote] |
| | NixOS(Wayland) | NixOS(Xorg) |
| --------------------------- | :------------------------------------------------------------------------------------------------------------------ | :------------------------------------------------------------------------------------------------------------------ |
| **Window Manager** | [Hyprland][Hyprland] | [i3][i3] |
| **Terminal Emulator** | [Zellij][Zellij] + [Kitty][Kitty] | [Zellij][Zellij] + [Kitty][Kitty] |
| **Bar** | [Waybar][Waybar] | [polybar][polybar] |
| **Application Launcher** | [anyrun][anyrun] | [rofi][rofi] |
| **Notification Daemon** | [Mako][Mako] | [Dunst][Dunst] |
| **Display Manager** | [GDM][GDM] | [GDM][GDM] |
| **Color Scheme** | [Catppuccin][Catppuccin] | [Catppuccin][Catppuccin] |
| **network management tool** | [NetworkManager][NetworkManager] | [NetworkManager][NetworkManager] |
| **Input method framework** | [Fcitx5][Fcitx5] | [Fcitx5][Fcitx5] |
| **System resource monitor** | [Btop][Btop] | [Btop][Btop] |
| **File Manager** | [Yazi][Yazi] + [thunar][thunar] | [Yazi][Yazi] + [thunar][thunar] |
| **Shell** | [Nushell][Nushell] + [Starship][Starship] | [Nushell][Nushell] + [Starship][Starship] |
| **Music Player** | [mpd][mpd], [ncmpcpp][ncmpcpp], [mpc][mpc], [Netease-cloud-music-gtk][netease-cloud-music-gtk] | [Netease-cloud-music-gtk][netease-cloud-music-gtk] |
| **Media Player** | [mpv][mpv] | [mpv][mpv] |
| **Text Editor** | [Neovim][Neovim] + [DoomEmacs][DoomEmacs] | [Neovim][Neovim] + [DoomEmacs][DoomEmacs] |
| **Fonts** | [Nerd fonts][Nerd fonts] | [Nerd fonts][Nerd fonts] |
| **Image Viewer** | [imv][imv] | [imv][imv] |
| **Screenshot Software** | [flameshot][flameshot] + [grim][grim] | [flameshot][flameshot] |
| **Screen Recording** | [OBS][OBS] | [OBS][OBS] |
| **Filesystem & Encryption** | tmpfs on `/`, [Btrfs][Btrfs] subvolumes on a [LUKS][LUKS] encrypted partition for persistent, unlock via passphrase | tmpfs on `/`, [Btrfs][Btrfs] subvolumes on a [LUKS][LUKS] encrypted partition for persistent, unlock via passphrase |
| **Secure Boot** | [lanzaboote][lanzaboote] | [lanzaboote][lanzaboote] |
Wallpapers: https://github.com/ryan4yin/wallpapers
@@ -73,8 +85,7 @@ Wallpapers: https://github.com/ryan4yin/wallpapers
## I3 + AstroNvim
![](./_img/i3_2023-07-29_1.webp)
![](./_img/i3_2023-07-29_2.webp)
![](./_img/i3_2023-07-29_1.webp) ![](./_img/i3_2023-07-29_2.webp)
## Neovim
@@ -90,14 +101,19 @@ See [./secrets](./secrets) for details.
## How to Deploy this Flake?
> :red_circle: **IMPORTANT**: **You should NOT deploy this flake directly on your machine :exclamation: It will not succeed.**
> This flake contains my hardware configuration(such as [hardware-configuration.nix](hosts/idols-ai/hardware-configuration.nix), [cifs-mount.nix](https://github.com/ryan4yin/nix-config/blob/v0.1.1/hosts/idols_ai/cifs-mount.nix), [Nvidia Support](https://github.com/ryan4yin/nix-config/blob/v0.1.1/hosts/idols-ai/default.nix#L77-L91), etc.) which is not suitable for your hardwares,
> and requires my private secrets repository [ryan4yin/nix-secrets](https://github.com/ryan4yin/nix-config/tree/main/secrets) to deploy.
> You may use this repo as a reference to build your own configuration.
> :red_circle: **IMPORTANT**: **You should NOT deploy this flake directly on your machine
> :exclamation: It will not succeed.** This flake contains my hardware configuration(such as
> [hardware-configuration.nix](hosts/idols-ai/hardware-configuration.nix),
> [cifs-mount.nix](https://github.com/ryan4yin/nix-config/blob/v0.1.1/hosts/idols_ai/cifs-mount.nix),
> [Nvidia Support](https://github.com/ryan4yin/nix-config/blob/v0.1.1/hosts/idols-ai/default.nix#L77-L91),
> etc.) which is not suitable for your hardwares, and requires my private secrets repository
> [ryan4yin/nix-secrets](https://github.com/ryan4yin/nix-config/tree/main/secrets) to deploy. You
> may use this repo as a reference to build your own configuration.
For NixOS:
> To deploy this flake from NixOS's official ISO image(purest installation method), please refer to [./nixos-installer/](./nixos-installer/)
> To deploy this flake from NixOS's official ISO image(purest installation method), please refer to
> [./nixos-installer/](./nixos-installer/)
> Need to restart the machine when switching between `wayland` and `xorg`.
@@ -136,7 +152,8 @@ just ha debug
# just fe debug
```
> [What y'all will need when Nix drives you to drink.](https://www.youtube.com/watch?v=Eni9PPPPBpg) (copy from hlissner's dotfiles, it really matches my feelings when I first started using NixOS...)
> [What y'all will need when Nix drives you to drink.](https://www.youtube.com/watch?v=Eni9PPPPBpg)
> (copy from hlissner's dotfiles, it really matches my feelings when I first started using NixOS...)
## How to create & managage VM from this flake?
@@ -146,14 +163,15 @@ use `aquamarine` as an example, we can create a virtual machine with the followi
# 1. generate a proxmox vma image file
nom build .#aquamarine # `nom`(nix-output-monitor) can be replaced by the standard command `nix`
# 2. upload the genereated image to proxmox server's backup directory `/var/lib/vz/dump`
# 2. upload the generated image to proxmox server's backup directory `/var/lib/vz/dump`
# please replace the vma file name with the one you generated in step 1.
rsync -avz --progress --copy-links result root@um560:/var/lib/vz/dump/vzdump-qemu-aquamarine.vma.zst
# 3. the image we uploaded will be listed in proxmox web ui's this page: [storage 'local'] -> [backups], we can restore a vm from it via the web ui now.
```
Once the virtual machine `aquamarine` is created, we can deploy updates to it with the following commands:
Once the virtual machine `aquamarine` is created, we can deploy updates to it with the following
commands:
```shell
# 1. add the ssh key to ssh-agent
@@ -164,7 +182,8 @@ ssh-add /etc/agenix/ssh-key-romantic
colmena apply --on '@dist-build' --show-trace
```
If you're not familiar with remote deployment, please read this tutorial first: [Remote Deployment - NixOS & Flakes Book](https://nixos-and-flakes.thiscute.world/best-practices/remote-deployment)
If you're not familiar with remote deployment, please read this tutorial first:
[Remote Deployment - NixOS & Flakes Book](https://nixos-and-flakes.thiscute.world/best-practices/remote-deployment)
## References
@@ -179,17 +198,22 @@ Other dotfiles that inspired me:
- [davidtwco/veritas](https://github.com/davidtwco/veritas)
- [gvolpe/nix-config](https://github.com/gvolpe/nix-config)
- [Ruixi-rebirth/flakes](https://github.com/Ruixi-rebirth/flakes)
- [fufexan/dotfiles](https://github.com/fufexan/dotfiles): gtk theme, xdg, git, media, anyrun, etc.
- [nix-community/srvos](https://github.com/nix-community/srvos): a collection of opinionated and sharable NixOS configurations for servers
- [fufexan/dotfiles](https://github.com/fufexan/dotfiles): gtk theme, xdg, git, media, anyrun,
etc.
- [nix-community/srvos](https://github.com/nix-community/srvos): a collection of opinionated and
sharable NixOS configurations for servers
- Modularized NixOS Configuration
- [hlissner/dotfiles](https://github.com/hlissner/dotfiles)
- [viperML/dotfiles](https://github.com/viperML/dotfiles)
- Hyprland(wayland)
- [notwidow/hyprland](https://github.com/notwidow/hyprland): This is where I start my hyprland journey.
- [HeinzDev/Hyprland-dotfiles](https://github.com/HeinzDev/Hyprland-dotfiles): Refer to the waybar configuration here.
- [notwidow/hyprland](https://github.com/notwidow/hyprland): This is where I start my hyprland
journey.
- [HeinzDev/Hyprland-dotfiles](https://github.com/HeinzDev/Hyprland-dotfiles): Refer to the waybar
configuration here.
- [linuxmobile/kaku](https://github.com/linuxmobile/kaku)
- I3 Window Manager
- [endeavouros-i3wm-setup](https://github.com/endeavouros-team/endeavouros-i3wm-setup): I started using i3 here, and my i3 configuration is also based on it, but made a lot of changes.
- [endeavouros-i3wm-setup](https://github.com/endeavouros-team/endeavouros-i3wm-setup): I started
using i3 here, and my i3 configuration is also based on it, but made a lot of changes.
- [denisse-dev/dotfiles](https://github.com/denisse-dev/dotfiles)
- Neovim/AstroNvim
- [maxbrunet/dotfiles](https://github.com/maxbrunet/dotfiles): astronvim with nix flakes.

View File

@@ -3,4 +3,3 @@
1. `base`: The base module that is suitable for both Linux and macOS.
2. `linux`: Linux-specific configuration.
3. `darwin`: macOS-specific configuration.

View File

@@ -3,4 +3,3 @@
1. `server`: Configuration which is suitable for both servers and desktops.
1. `desktop`: Configuration for desktop environments, such as Hyprland, I3, etc.
1. `core.nix`: Minimal home-manager's config

View File

@@ -1,4 +1,3 @@
# Editors
See [desktop/editors/](../../desktop/editors/) for more details.

View File

@@ -1,21 +1,25 @@
# Termianl Emulators
# Terminal Emulators
I used to spend a lot of time on terminal emulators, to make them match my taste,
but now I found that it's not worth it, **Zellij can provide a user-friendly and unified user experience for all terminal emulators! without any pain**!
I used to spend a lot of time on terminal emulators, to make them match my taste, but now I found
that it's not worth it, **Zellij can provide a user-friendly and unified user experience for all
terminal emulators! without any pain**!
Currently, I only use the most basic features of terminal emulators, such as true color, graphics protocol, etc.
Other features such as tabs, scrollback buffer, select/search/copy, etc, are all provided by zellij!
Currently, I only use the most basic features of terminal emulators, such as true color, graphics
protocol, etc. Other features such as tabs, scrollback buffer, select/search/copy, etc, are all
provided by zellij!
My current terminal emulators are:
1. kitty: My main terminal emulator.
1. to select/copy a large mount of text, We should do some tricks via kitty's `scrollback_pager` with neovim, it's really painful: <https://github.com/kovidgoyal/kitty/issues/719>
1. to select/copy a large mount of text, We should do some tricks via kitty's `scrollback_pager`
with neovim, it's really painful: <https://github.com/kovidgoyal/kitty/issues/719>
2. wezterm: My secondary terminal emulator.
1. its search ability is very basic, and it's not easy to use.
1. its scrollback buffer's copy mode is very like vim, which is nice, but zellij's even better, it can use neovim as its default scrollback buffer's editor without any pain!
1. its search ability is very basic, and it's not easy to use.
1. its scrollback buffer's copy mode is very like vim, which is nice, but zellij's even better,
it can use neovim as its default scrollback buffer's editor without any pain!
3. foot: a fast, lightweight and minimalistic Wayland terminal emulator.
1. foot only do the things a terminal emulator should do, no more, no less.
1. It's really suitable for tiling window manager or zellij users!
1. foot only do the things a terminal emulator should do, no more, no less.
1. It's really suitable for tiling window manager or zellij users!
## 'xterm-kitty': unknown terminal type when `ssh` into a remote host or `sudo xxx`
@@ -23,45 +27,55 @@ My current terminal emulators are:
> https://wezfurlong.org/wezterm/config/lua/config/term.html
kitty set `TERM` to `xterm-kitty` by default, and TUI apps like `viu`, `yazi`, `curses` will try to search in the host's [terminfo(terminal capability data base)](https://linux.die.net/man/5/terminfo) for value of `TERM` to determine the capabilities of the terminal.
kitty set `TERM` to `xterm-kitty` by default, and TUI apps like `viu`, `yazi`, `curses` will try to
search in the host's [terminfo(terminal capability data base)](https://linux.die.net/man/5/terminfo)
for value of `TERM` to determine the capabilities of the terminal.
But when you `ssh` into a remote host, the remote host is very likely to not have `xterm-kitty` in its terminfo, so you will get this error:
But when you `ssh` into a remote host, the remote host is very likely to not have `xterm-kitty` in
its terminfo, so you will get this error:
```
'xterm-kitty': unknown terminal type
```
Or when you `sudo xxx`, `sudo` won't preserve the `TERM` variable, it will be reset to root's default `TERM` value, which is `xterm` or `xterm-256color` in most linux distributions, so you will get this error:
Or when you `sudo xxx`, `sudo` won't preserve the `TERM` variable, it will be reset to root's
default `TERM` value, which is `xterm` or `xterm-256color` in most linux distributions, so you will
get this error:
```
'xterm-256color': unknown terminal type
```
or
or
```
Error opening terminal: xterm-kitty.
```
NixOS preserve the `TERMINFO` and `TERMINFO_DIRS` environment variables, for `root` and the `wheel` group: [nixpkgs/nixos/modules/config/terminfo.nix](https://github.com/NixOS/nixpkgs/blob/nixos-23.11/nixos/modules/config/terminfo.nix#L18)
NixOS preserve the `TERMINFO` and `TERMINFO_DIRS` environment variables, for `root` and the `wheel`
group:
[nixpkgs/nixos/modules/config/terminfo.nix](https://github.com/NixOS/nixpkgs/blob/nixos-23.11/nixos/modules/config/terminfo.nix#L18)
For nix-darwin, take a look at <https://github.com/LnL7/nix-darwin/wiki/Terminfo-issues>
### Solutions
Simplest solution, it will automatically copy over the terminfo files and also magically enable shell integration on the remote machine:
Simplest solution, it will automatically copy over the terminfo files and also magically enable
shell integration on the remote machine:
```
kitten ssh user@host
```
Or if you do not care about kitty's features(such as true color & graphics protocol), you can simply set `TERM` to `xterm-256color`, which is built-in in most linux distributions:
Or if you do not care about kitty's features(such as true color & graphics protocol), you can simply
set `TERM` to `xterm-256color`, which is built-in in most linux distributions:
```
export TERM=xterm-256color
```
If you need kitty's features, but do not like the magic of `kitten`, you can manually install kitty's terminfo on the remote host:
If you need kitty's features, but do not like the magic of `kitten`, you can manually install
kitty's terminfo on the remote host:
```bash
# install on ubuntu / debian
@@ -70,4 +84,3 @@ sudo apt-get install kitty-terminfo
# or copy from local machine
infocmp -a xterm-kitty | ssh myserver tic -x -o \~/.terminfo /dev/stdin
```

View File

@@ -6,7 +6,9 @@
> https://langserver.org/
The Language Server Protocol (LSP) is an open, JSON-RPC-based protocol for use between source code editors or integrated development environments (IDEs) and servers that provide programming language-specific features like:
The Language Server Protocol (LSP) is an open, JSON-RPC-based protocol for use between source code
editors or integrated development environments (IDEs) and servers that provide programming
language-specific features like:
- motions such as go-to-definition, find-references, hover.
- **code completion**
@@ -15,10 +17,11 @@ The Language Server Protocol (LSP) is an open, JSON-RPC-based protocol for use b
- syntax highlighting (use Tree-sitter instead)
- code formatting (use a dedicated formatter instead)
The goal of the protocol is to allow programming language support to be implemented and distributed independently of any given editor or IDE.
The goal of the protocol is to allow programming language support to be implemented and distributed
independently of any given editor or IDE.
LSP was originally developed for Microsoft Visual Studio Code and is now an open standard.
In the early 2020s LSP quickly became a "norm" for language intelligence tools providers.
LSP was originally developed for Microsoft Visual Studio Code and is now an open standard. In the
early 2020s LSP quickly became a "norm" for language intelligence tools providers.
### Tree-sitter
@@ -26,7 +29,9 @@ In the early 2020s LSP quickly became a "norm" for language intelligence tools p
> https://www.reddit.com/r/neovim/comments/1109wgr/treesitter_vs_lsp_differences_ans_overlap/
Tree-sitter is a parser generator tool and an **incremental parsing** library. It can build a concrete syntax tree for a source file and efficiently update the syntax tree as the source file is edited.
Tree-sitter is a parser generator tool and an **incremental parsing** library. It can build a
concrete syntax tree for a source file and efficiently update the syntax tree as the source file is
edited.
It is used by many editors and IDEs to provide:
@@ -38,17 +43,22 @@ It is used by many editors and IDEs to provide:
- such as join/split lines, structural editing, cursor motion, etc.
**Treesitter process each file independently**, and it is not aware of the semantics of your code.
For example, it does not know does a function/variable really exist, or what is the type/return-type of a variable. This is where LSP comes in.
For example, it does not know does a function/variable really exist, or what is the type/return-type
of a variable. This is where LSP comes in.
The LSP server parses the code much more deeply and it **not only parses a single file but your whole project**.
So, the LSP server will know whether a function/variable does exist with the same type/return-type. If it does not, it will mark it as an error.
The LSP server parses the code much more deeply and it **not only parses a single file but your
whole project**. So, the LSP server will know whether a function/variable does exist with the same
type/return-type. If it does not, it will mark it as an error.
**LSP does understand the code semantically, while Treesitter only cares about correct syntax**.
#### LSP vs Tree-sitter
- Tree-sitter: lightweight, fast, but limited knowledge of your code. mainly used for **syntax highlighting, indentation, and folding/refactoring in a single file**.
- LSP: heavy and slow on large projects, but it has a deep understanding of your code. mainly used for **code completion, refactoring in the projects, errors/warnings, and other semantic-aware features**.
- Tree-sitter: lightweight, fast, but limited knowledge of your code. mainly used for **syntax
highlighting, indentation, and folding/refactoring in a single file**.
- LSP: heavy and slow on large projects, but it has a deep understanding of your code. mainly used
for **code completion, refactoring in the projects, errors/warnings, and other semantic-aware
features**.
### Formatter vs Linter
@@ -56,7 +66,10 @@ Linting is distinct from Formatting because:
1. **formatting** only restructures how code appears.
1. `prettier` is a popular formatter.
1. **linting** analyzes how the code runs and detects errors, it may also suggest improvements such as replace `var` with `let` or `const`.
1. **linting** analyzes how the code runs and detects errors, it may also suggest improvements such
as replace `var` with `let` or `const`.
Formatters and Linters process each file independently, they do not need to know about other files in the project.
* [ ]
Formatters and Linters process each file independently, they do not need to know about other files
in the project.
- [ ]

View File

@@ -10,15 +10,18 @@ And `Zellij` for a smooth and stable terminal experience.
## Tips
1. Many useful keys are already provided by vim, check vim/neovim's docs before you install a new plugin / reinvent the wheel.
1. After using Emacs/Neovim more skillfully, I strongly recommend that you read the official documentation of Neovim/vim:
1. Many useful keys are already provided by vim, check vim/neovim's docs before you install a new
plugin / reinvent the wheel.
1. After using Emacs/Neovim more skillfully, I strongly recommend that you read the official
documentation of Neovim/vim:
1. <https://vimhelp.org/>: The official vim documentation.
1. <https://neovim.io/doc/user/>: Neovim's official user documentation.
1. Use Zellij for terminal related operations, and use Neovim/Helix for editing.
1. As for Emacs, Use its GUI version & terminal emulator `vterm` for terminal related operations.
1. Two powerful file search & jump tools:
1. Tree-view plugins are beginner-friendly and intuitive, but they're not very efficient.
1. **Search by the file path**: Useful when you're familiar with the project structure, especially on a large project.
1. **Search by the file path**: Useful when you're familiar with the project structure, especially
on a large project.
1. **Search by the content**: Useful when you're familiar with the code.
## Tutorial
@@ -27,13 +30,16 @@ Type `:tutor`(`:Tutor` in Neovim) to learn the basics usage of vim/neovim.
## VIM's Cheetsheet
> Here only record my commonly used keys, to see **a more comprehensive cheetsheet**: <https://vimhelp.org/quickref.txt.html>
> Here only record my commonly used keys, to see **a more comprehensive cheetsheet**:
> <https://vimhelp.org/quickref.txt.html>
Both Emacs-Evil & Neovim are compatible with vim, sothe key-bindings described here are common in both Emacs-Evil, Neovim & vim.
Both Emacs-Evil & Neovim are compatible with vim, sothe key-bindings described here are common in
both Emacs-Evil, Neovim & vim.
### Terminal Related
I mainly use Zellij for terminal related operations, here is its terminal shortcuts I use frequently now:
I mainly use Zellij for terminal related operations, here is its terminal shortcuts I use frequently
now:
| Action | Zellij's Shortcut |
| ------------------------- | ----------------- |
@@ -76,10 +82,12 @@ I mainly use Zellij for terminal related operations, here is its terminal shortc
Text Objects:
- **sentence**: text ending at a '.', '!' or '?' followed by either the end of a line, or by a space or tab.
- **sentence**: text ending at a '.', '!' or '?' followed by either the end of a line, or by a space
or tab.
- **paragraph**: text ending at a blank line.
- **section**: text starting with a section header and ending at the start of the next section header (or at the end of the file). - The "`]]`" and "`[[`" commands stop at the '`{`' in the first column. This is
useful to find the start of a function in a C/Go/Java/... program.
- **section**: text starting with a section header and ending at the start of the next section
header (or at the end of the file). - The "`]]`" and "`[[`" commands stop at the '`{`' in the
first column. This is useful to find the start of a function in a C/Go/Java/... program.
### Text Manipulation
@@ -99,7 +107,7 @@ Basics:
| Toggle text's case | `~` |
| Convert to uppercase | `U` (visual mode) |
| Convert to lowercase | `u` (visual mode) |
| Align the selected conent | `:center`/`:left`/`:right` |
| Align the selected content | `:center`/`:left`/`:right` |
Misc:
@@ -116,7 +124,7 @@ Misc:
| Action | |
| ------------------------------------------------------------------------- | -------------- |
| Sort tye selected lines | `:sort` |
| Sort the selected lines | `:sort` |
| Join Selection of Lines With Space | `:join` or `J` |
| Join without spaces | `:join!` |
| Enter Insert mode at the start/end of the line | `I` / `A` |
@@ -161,7 +169,8 @@ Advance Techs:
| Replace all the lines | `:% s/old/new/g` |
| Replace all the lines with regex | `:% s@\vhttp://(\w+)@https://\1@gc` |
1. `\v` means means that in the regex pattern after it can be used without backslash escaping(similar to python's raw string).
1. `\v` means means that in the regex pattern after it can be used without backslash
escaping(similar to python's raw string).
2. `\1` means the first matched group in the pattern.
### Replace in the specific lines

View File

@@ -2,23 +2,24 @@
## S-expression data(Lisp)
- paredit/[lispy](https://github.com/doomemacs/doomemacs/tree/master/modules/editor/lispy): too complex.
- paredit/[lispy](https://github.com/doomemacs/doomemacs/tree/master/modules/editor/lispy): too
complex.
- [evil-cleverparens](https://github.com/emacs-evil/evil-cleverparens): simple and useful.
- [parinfer(par-in-fer)](https://shaunlebron.github.io/parinfer/): morden, simple, elegant and useful, but works not well with some other completion plugins...
- to make parinfer works, you should disable sexp & smartparens in any lisp mode.
- [parinfer(par-in-fer)](https://shaunlebron.github.io/parinfer/): morden, simple, elegant and
useful, but works not well with some other completion plugins...
- to make parinfer works, you should disable sexp & smartparens in any lisp mode.
Some plugins:
- Emacs
- [parinfer-rusT-mode](https://github.com/justinbarclay/parinfer-rust-mode)
- [parinfer-rusT-mode](https://github.com/justinbarclay/parinfer-rust-mode)
- Neovim
- [parinfer-rust](https://github.com/eraserhd/parinfer-rust)
- <https://github.com/Olical/conjure>
- [parinfer-rust](https://github.com/eraserhd/parinfer-rust)
- <https://github.com/Olical/conjure>
- Helix
- [parinfer #4090 - Helix](https://github.com/helix-editor/helix/discussions/4090)
- [parinfer #4090 - Helix](https://github.com/helix-editor/helix/discussions/4090)
## Other Languages
1. treesitter
1. ...

View File

@@ -6,17 +6,19 @@
2. Org Mode
3. Lisp Coding
4. A top-level tutorial for Emacs(Chinese): <https://nyk.ma/tags/emacs/>
5. A Beginner's Guide to Emacs(Chinese): <https://github.com/emacs-tw/emacs-101-beginner-survival-guide>
5. A Beginner's Guide to Emacs(Chinese):
<https://github.com/emacs-tw/emacs-101-beginner-survival-guide>
## Screenshot
![](/_img/emacs-2024-01-07.webp)
## Usefull Links
## Useful Links
- Framework: <https://github.com/doomemacs/doomemacs>
- key bindings:
- source code: <https://github.com/doomemacs/doomemacs/blob/master/modules/config/default/%2Bevil-bindings.el>
- source code:
<https://github.com/doomemacs/doomemacs/blob/master/modules/config/default/%2Bevil-bindings.el>
- docs: <https://github.com/doomemacs/doomemacs/blob/master/modules/editor/evil/README.org>
- module index: <https://github.com/doomemacs/doomemacs/blob/master/docs/modules.org>
- LSP Client: <https://github.com/manateelazycat/lsp-bridge>
@@ -44,7 +46,7 @@ when in doubt, run `doom sync`!
```bash
# testing
just emacs-test
jsut emacs-purge
just emacs-purge
just emacs-reload
# clear test data
@@ -59,14 +61,16 @@ just emacs-clean
- So vim/neovim is still the best choice for servers.
- Emacs's markdown-mode works not well with tables, see:
- https://github.com/jrblevin/markdown-mode/issues/380
- I use git command frequently, but doomemacs only autoupdates status of git diff / treemacs when using magit.
- I use git command frequently, but doomemacs only autoupdates status of git diff / treemacs when
using magit.
- I have to learn magit to avoid this issue...
- GitHub's orgmode support is not well, Markdown is better for GitHub.
- Use markdown for repo's README.md, and use orgmode for my personal notes and docs only.
## Cheetsheet
Here is the cheetsheet related to my DoomEmacs configs. Please read vim's common cheetsheet at [../README.md](../README.md) before reading the following.
Here is the cheetsheet related to my DoomEmacs configs. Please read vim's common cheetsheet at
[../README.md](../README.md) before reading the following.
### Basics
@@ -98,7 +102,8 @@ Here is the cheetsheet related to my DoomEmacs configs. Please read vim's common
### File Tree
- treemacs: <https://github.com/Alexander-Miller/treemacs/blob/master/src/elisp/treemacs-mode.el>
- treemacs-evil: <https://github.com/Alexander-Miller/treemacs/blob/master/src/extra/treemacs-evil.el>
- treemacs-evil:
<https://github.com/Alexander-Miller/treemacs/blob/master/src/extra/treemacs-evil.el>
| Action | Shortcut |
| ------------------------------------- | --------- |
@@ -199,8 +204,9 @@ Magit is a powerful tool that make git operations easy and intuitive.
Shortcuts in magit's pane:
> When run `git commit` / `git add` / `git push` /... via magit, multiple Arguments can be set.
> Set arguments won't trigger a git command immediately. Magit will try to run a git command only after an Action key is pressed.
> When run `git commit` / `git add` / `git push` /... via magit, multiple Arguments can be set. Set
> arguments won't trigger a git command immediately. Magit will try to run a git command only after
> an Action key is pressed.
| Action | Shortcut |
| -------------------------------------------------- | --------------------------------------------- |
@@ -220,4 +226,5 @@ Shortcuts in magit's pane:
| Fold/Unfold | `TAB` |
| Show details of the current unit(commit/stage/...) | `<ENTER>` |
KeyBinding full list: <https://github.com/emacs-evil/evil-collection/tree/master/modes/magit#key-bindings>
KeyBinding full list:
<https://github.com/emacs-evil/evil-collection/tree/master/modes/magit#key-bindings>

View File

@@ -1,11 +1,14 @@
# Helix Editor
Neovim is really powerful, and have a very active community. I use it as my main editor, and I'm very happy with it. I use it for everything, from writing code to writing this document.
Neovim is really powerful, and have a very active community. I use it as my main editor, and I'm
very happy with it. I use it for everything, from writing code to writing this document.
But its configuration is a bit complex, and finding the right plugins, writing configurations, and keeping everything up to date is not easy.
But its configuration is a bit complex, and finding the right plugins, writing configurations, and
keeping everything up to date is not easy.
That's why I'm interested in Helix, Helix is similar to Neovim, but it's more opinionated, and it's batteries included.
Whether I'll switch my main editor to Helix or not, it gives me a lot of ideas on how to improve my Neovim workflow.
That's why I'm interested in Helix, Helix is similar to Neovim, but it's more opinionated, and it's
batteries included. Whether I'll switch my main editor to Helix or not, it gives me a lot of ideas
on how to improve my Neovim workflow.
## Tutorial
@@ -14,30 +17,48 @@ Use `:tutor` in helix to start the tutorial.
## Differences between Neovim and Helixer
1. Selecting first, then action.
1. Helix: delete 2 word: `2w` then `x`. You can always see what you're selecting before you apply the action.
2. Neovim: delete 2 word: `d`. then `2w`. No visual feedback before you apply the action.
1. Helix - Morden builtin features: LSP, tree-sitter, fuzzy finder, multi cursors, surround and more.
1. They're all available in Neovim too, but you need to find and use the right plugins manually, which takes time and effort.
1. Helix is built in Rust from scratch. The result is a much smaller codebase and a modern set of defaults. No VimScript. No Lua.
1. Neovim contains a lot of VimScript, and lua is too dynamic, it's hard to debug.
1. Personally I'm glad to take a look at a Rust codebase, but not a VimScript/Lua codebase.
1. Neovim have a very activate plugin ecosystem, and it's easy to find plugins for almost everything.
1. Helix is still new, and it even do have a stable plugin system yet. A PR to add a plugin system is still envolving: <https://github.com/helix-editor/helix/pull/8675>
2. Neovim has intergrated terminal, and it's very powerful. It's quite similar to VSCode's intergrated terminal. I use it a lot.
1. Helix doesn't have a intergrated terminal yet, as it's complicated to implement. Users are recommended to use tmux/Zellij or Wezterm/Kitty to implement this feature instead.
1. <https://github.com/helix-editor/helix/issues/1976#issuecomment-1091074719>
1. <https://github.com/helix-editor/helix/pull/4649>
1. **My Neovim often gets stuck when I switch to [toggleterm.nvim](https://github.com/akinsho/toggleterm.nvim), this Helix issue made me consider to switch from this Neovim plugin to Zellij**.
1. Helix do not have a tree-view panel, it's recommended to use Yazi/ranger/Broot instead, and open Helix in them.
1. a tree-view plugin may be added after the plugin system is stable, but no one knows when it will be.
2. and some Helix users stated that they don't need a tree-view plugin, Helix's file picker is useful and good enough.
1. It seems Helix lacks a global substitution command, you should run it in another window(via wm or Zellij).
1. <https://github.com/helix-editor/helix/issues/196>
1. Neovim's substitution command allow you to preview the changes before you apply it, and it's very useful. if I switch to Helix, I'll need to find some other tools with similar feature(such as https://github.com/ms-jpq/sad).
1. Complexity and Maintenance Costs vs Batteries Included: <https://github.com/helix-editor/helix/discussions/6356>
1. Helix: delete 2 word: `2w` then `x`. You can always see what you're selecting before you apply
the action.
2. Neovim: delete 2 word: `d`. then `2w`. No visual feedback before you apply the action.
1. Helix - Morden builtin features: LSP, tree-sitter, fuzzy finder, multi cursors, surround and
more.
1. They're all available in Neovim too, but you need to find and use the right plugins manually,
which takes time and effort.
1. Helix is built in Rust from scratch. The result is a much smaller codebase and a modern set of
defaults. No VimScript. No Lua.
1. Neovim contains a lot of VimScript, and lua is too dynamic, it's hard to debug.
1. Personally I'm glad to take a look at a Rust codebase, but not a VimScript/Lua codebase.
1. Neovim have a very activate plugin ecosystem, and it's easy to find plugins for almost
everything.
1. Helix is still new, and it even do have a stable plugin system yet. A PR to add a plugin
system is still envolving: <https://github.com/helix-editor/helix/pull/8675>
1. Neovim has integrated terminal, and it's very powerful. It's quite similar to VSCode's integrated
terminal. I use it a lot.
1. Helix doesn't have a integrated terminal yet, as it's complicated to implement. Users are
recommended to use tmux/Zellij or Wezterm/Kitty to implement this feature instead.
1. <https://github.com/helix-editor/helix/issues/1976#issuecomment-1091074719>
1. <https://github.com/helix-editor/helix/pull/4649>
1. **My Neovim often gets stuck when I switch to
[toggleterm.nvim](https://github.com/akinsho/toggleterm.nvim), this Helix issue made me
consider to switch from this Neovim plugin to Zellij**.
1. Helix do not have a tree-view panel, it's recommended to use Yazi/ranger/Broot instead, and open
Helix in them.
1. a tree-view plugin may be added after the plugin system is stable, but no one knows when it
will be.
2. and some Helix users stated that they don't need a tree-view plugin, Helix's file picker is
useful and good enough.
1. It seems Helix lacks a global substitution command, you should run it in another window(via wm or
Zellij).
1. <https://github.com/helix-editor/helix/issues/196>
1. Neovim's substitution command allow you to preview the changes before you apply it, and it's
very useful. if I switch to Helix, I'll need to find some other tools with similar
feature(such as https://github.com/ms-jpq/sad).
1. Complexity and Maintenance Costs vs Batteries Included:
<https://github.com/helix-editor/helix/discussions/6356>
I think Use Helix/Neovim within a terminal file manager(Yazi/ranger/Broot) and Zellij is a good
idea. It's quite different from the workflow I migrated from VSCode/JetBrains before, I'm very
interested in it.
I think Use Helix/Neovim within a terminal file manager(Yazi/ranger/Broot) and Zellij is a good idea.
It's quite different from the workflow I migrated from VSCode/JetBrains before, I'm very interested in it.
In Neovim I can make the workflow similar to VSCode/JetBrains by using some plugins, but Helix forces me to get out of my comfort zone, and try something new.
In Neovim I can make the workflow similar to VSCode/JetBrains by using some plugins, but Helix
forces me to get out of my comfort zone, and try something new.

View File

@@ -1,14 +1,14 @@
# Neovim Editor
My Neovim config based on [AstroNvim](https://github.com/AstroNvim/AstroNvim).
For more details, visit the [AstroNvim website](https://astronvim.com/).
My Neovim config based on [AstroNvim](https://github.com/AstroNvim/AstroNvim). For more details,
visit the [AstroNvim website](https://astronvim.com/).
This document outlines neovim's configuration structure and various shortcuts/commands for efficient usage.
This document outlines neovim's configuration structure and various shortcuts/commands for efficient
usage.
## Screenshots
![](/_img/astronvim_2023-07-13_00-39.webp)
![](/_img/hyprland_2023-07-29_2.webp)
![](/_img/astronvim_2023-07-13_00-39.webp) ![](/_img/hyprland_2023-07-29_2.webp)
## Configuration Structure
@@ -47,7 +47,8 @@ just nvim-clear
## Cheetsheet
Here is the cheetsheet related to my Neovim configs. Please read vim's common cheetsheet at [../README.md](../README.md) before reading the following.
Here is the cheetsheet related to my Neovim configs. Please read vim's common cheetsheet at
[../README.md](../README.md) before reading the following.
### Incremental Selection
@@ -62,15 +63,16 @@ Provided by nvim-treesitter.
### Search and Jump
Provided by [flash.nvim](https://github.com/folke/flash.nvim), it's a intelligent search and jump plugin.
Provided by [flash.nvim](https://github.com/folke/flash.nvim), it's a intelligent search and jump
plugin.
1. It enhaces the default search and jump behavior of neovim.(search with prefix `/`)
1. It enhances the default search and jump behavior of neovim.(search with prefix `/`)
| Action | Shortcut |
| ----------------- | ------------------------------------------------------------------------------------------------------------- |
| Search | `/`(normal search), `s`(disable all code highlight, only highlight matches) |
| Treesitter Search | `yR`,`dR`, `cR`, `vR`, `ctrl+v+R`(arround your matches, all the surrounding Treesitter nodes will be labeled) |
| Remote Flash | `yr`, `dr`, `cr`, (arround your matches, all the surrounding Treesitter nodes will be labeled) |
| Action | Shortcut |
| ----------------- | ------------------------------------------------------------------------------------------------------------ |
| Search | `/`(normal search), `s`(disable all code highlight, only highlight matches) |
| Treesitter Search | `yR`,`dR`, `cR`, `vR`, `ctrl+v+R`(around your matches, all the surrounding Treesitter nodes will be labeled) |
| Remote Flash | `yr`, `dr`, `cr`, (around your matches, all the surrounding Treesitter nodes will be labeled) |
### Commands & Shortcuts
@@ -92,12 +94,8 @@ Provided by [flash.nvim](https://github.com/folke/flash.nvim), it's a intelligen
### Splitting and Buffers
|
| Action | Shortcut |
| --------------------- | ------------- |
| Horizontal Split | `\` |
| Vertical Split | `\|` |
| Close Buffer | `<Space> + c` |
| | Action | Shortcut | | --------------------- | ------------- | | Horizontal Split | `\` | |
Vertical Split | `\|` | | Close Buffer | `<Space> + c` |
### Editing and Formatting
@@ -129,9 +127,9 @@ Press `<Space> + D` to view available bindings and options.
### Search and Replace Globally
| Description | Shortcut |
| ------------------------------------------------------------ | ---------------------------------------------------------------- |
| Open spectre.nvim search and replace panel | `<Space> + ss` |
| Description | Shortcut |
| ------------------------------------------ | -------------- |
| Open spectre.nvim search and replace panel | `<Space> + ss` |
Search and replace via cli(fd + sad + delta):
@@ -139,7 +137,6 @@ Search and replace via cli(fd + sad + delta):
fd "\\.nix$" . | sad '<pattern>' '<replacement>' | delta
```
### Surrounding Characters
Provided by mini.surround plugin.

View File

@@ -1,30 +1,31 @@
# Encryption
We have GnuPG & password-store installed by default, mainly for password management, authentication & communication encryption.
We have GnuPG & password-store installed by default, mainly for password management, authentication
& communication encryption.
We also have LUKS2 for disk encryption on Linux, and [rclone](https://rclone.org/crypt/) for cross-platform data encryption & syncing.
We also have LUKS2 for disk encryption on Linux, and [rclone](https://rclone.org/crypt/) for
cross-platform data encryption & syncing.
[age](https://github.com/FiloSottile/age) may be more general for file encryption.
[Sops](https://github.com/getsops/sops/tree/main) can be used for file encryption too, if you prefer
[Sops](https://github.com/getsops/sops/tree/main) can be used for file encryption too, if you prefer
using a Cloud provider for key management.
## Asymmetric Encryption
Both age, Sops & GnuPG provide asymmetric encryption, which is useful for encrypting files for a specific user.
Both age, Sops & GnuPG provide asymmetric encryption, which is useful for encrypting files for a
specific user.
For morden use, age is recommended, as it use [AEAD encryption function - ChaCha20-Poly1305][age Format v1],
If you do not want to manage the keys by yourself, Sops is recommended, as it use KMS for key management.
For morden use, age is recommended, as it use [AEAD encryption function -
ChaCha20-Poly1305][age Format v1], If you do not want to manage the keys by yourself, Sops is
recommended, as it use KMS for key management.
## Symmetric Encryption
Both age & GnuPG provide symmetric encryption, which is useful for encrypting files for a specific user.
As described in [age Format v1][age Format v1], age use scrypt to encrypt and decrypt the file key with a provided passphrase,
which is more secure than GnuPG's symmetric encryption.
Both age & GnuPG provide symmetric encryption, which is useful for encrypting files for a specific
user.
As described in [age Format v1][age Format v1], age use scrypt to encrypt and decrypt the file key
with a provided passphrase, which is more secure than GnuPG's symmetric encryption.
[age Format v1]: https://age-encryption.org/v1

View File

@@ -1,10 +1,14 @@
# GNU Privacy Guard(GnuPG)
> Offical Website: https://www.gnupg.org/
> Official Website: https://www.gnupg.org/
The GNU Privacy Guard is a complete and free implementation of the OpenPGP standard as defined by RFC4880 (also known as **PGP**). GnuPG allows to encrypt and sign your data and communication, features a versatile key management system as well as access modules for all kind of public key directories.
The GNU Privacy Guard is a complete and free implementation of the OpenPGP standard as defined by
RFC4880 (also known as **PGP**). GnuPG allows to encrypt and sign your data and communication,
features a versatile key management system as well as access modules for all kind of public key
directories.
> In the following content, we will use GPG to refer to GnuPG tool, and PGP to refer to various concepts defined in the OepnPGP standard(e.g. PGP key, PGP key server).
> In the following content, we will use GPG to refer to GnuPG tool, and PGP to refer to various
> concepts defined in the OepnPGP standard(e.g. PGP key, PGP key server).
Key functions of GnuPG:
@@ -20,18 +24,21 @@ Main usage scenarios of GnuPG:
3. Manage your ssh key
4. Encrypt your data and store it somewhere.
GnuPG/OpenPGP is complex, so while using it, I have been looking forward to finding an encryption tool that is simple enough, functional enough, and widely adopted.
GnuPG/OpenPGP is complex, so while using it, I have been looking forward to finding an encryption
tool that is simple enough, functional enough, and widely adopted.
Currently I use both age & GnuPG:
1. Age for secrets encryption(ssh key & other secret files), it's simple and easy to use.
2. GnuPG for password-store and email encryption.
> At present, the safe and efficient use of GPG is probably combined with hardware keys such as yubikey. but I don't have one, so I won't talk about it here.
> At present, the safe and efficient use of GPG is probably combined with hardware keys such as
> yubikey. but I don't have one, so I won't talk about it here.
## Practical Cryptography for Developers
To use GnuGP without seamlessly, Some Practical Cryptography knowledge is required, here is dome tutorials:
To use GnuGP without seamlessly, Some Practical Cryptography knowledge is required, here is dome
tutorials:
- English version: <https://github.com/nakov/Practical-Cryptography-for-Developers-Book>
- Chinese version: <https://thiscute.world/tags/cryptography/>
@@ -50,12 +57,14 @@ Related Docs:
- [Predictable, Passphrase-Derived PGP Keys][Predictable, Passphrase-Derived PGP Keys]
- [OpenPGP - The almost perfect key pair][OpenPGP - The almost perfect key pair]
GnuPG generate every secret key separately, and encrypt them with a symmetric key derived from your
passphrase. OpenPGP standard defines
[String-to-Key (S2K)](https://datatracker.ietf.org/doc/html/rfc4880#section-3.7) algorithm to derive
a symmetric key from your passphrase.
GnuPG generate every secret key separately, and encrypt them with a symmetric key derived from your passphrase.
OpenPGP standard defines [String-to-Key (S2K)](https://datatracker.ietf.org/doc/html/rfc4880#section-3.7)
algorithm to derive a symmetric key from your passphrase.
GnuPG's [OpenPGP protocol specific options](https://gnupg.org/documentation/manuals/gnupg/OpenPGP-Options.html#OpenPGP-Options) shows that:
GnuPG's
[OpenPGP protocol specific options](https://gnupg.org/documentation/manuals/gnupg/OpenPGP-Options.html#OpenPGP-Options)
shows that:
```
--s2k-cipher-algo name
@@ -81,24 +90,31 @@ gpg --s2k-mode 3 --s2k-count 65011712 --s2k-digest-algo SHA512 --s2k-cipher-algo
To use the strongest options globally, you can specify these options in your `~/.gnupg/gpg.conf`.
I've added them to my Home Manager's `programs.gpg.settings` option.
### 1. PGP Key(Primary Key) generation
Key management is the core of OpenPGP standard / GnuPG.
GnuPG uses public-key cryptography so that users may communicate securely. In a public-key system, each user has a pair of keys consisting of a private key and a public key. **A user's private key is kept secret; it need **never be revealed. The public key may be given to anyone with whom the user wants to communicate**. GnuPG uses a somewhat more sophisticated scheme in which a user has a primary keypair and then zero or more additional subordinate keypairs. The primary and subordinate keypairs are bundled to facilitate key management and the bundle can often be considered simply as one keypair, or a keyring/keychain(which contains multiple sub key-pairs).
GnuPG uses public-key cryptography so that users may communicate securely. In a public-key system,
each user has a pair of keys consisting of a private key and a public key. **A user's private key is
kept secret; it need **never be revealed. The public key may be given to anyone with whom the user
wants to communicate\*\*. GnuPG uses a somewhat more sophisticated scheme in which a user has a
primary keypair and then zero or more additional subordinate keypairs. The primary and subordinate
keypairs are bundled to facilitate key management and the bundle can often be considered simply as
one keypair, or a keyring/keychain(which contains multiple sub key-pairs).
Let's generate a keypair interactively:
> Now in 2024, GnuPG 2.4.1 defaults to ECC algorithm (9) and Curve 25519 for ECC, which is morden and safe, I would recommend to use these defaults directly.
> Now in 2024, GnuPG 2.4.1 defaults to ECC algorithm (9) and Curve 25519 for ECC, which is morden
> and safe, I would recommend to use these defaults directly.
```bash
gpg --full-gen-key
```
This command will ask you for some algorithm related settings(ECC & Curve 25519), your personal info, and a strong passphrase to protect your PGP key. e.g.
This command will ask you for some algorithm related settings(ECC & Curve 25519), your personal
info, and a strong passphrase to protect your PGP key. e.g.
``` bash
```bash
gpg --full-gen-key
gpg (GnuPG) 2.4.1; Copyright (C) 2023 g10 Code GmbH
This is free software: you are free to change and redistribute it.
@@ -131,9 +147,9 @@ Is this correct? (y/N) y
GnuPG needs to construct a user ID to identify your key.
Real name:
Email address:
Comment:
Real name:
Email address:
Comment:
You selected this USER-ID:
"Ryan Yin (For pass For Work ssh only) <ryan4yin@linux.com>"
@@ -163,7 +179,7 @@ sub cv25519 2024-01-09 [E] [expires: 2034-01-04]
The generated keys are stored in `~/.gnupg` by default, the functions of each file are as follows:
``` bash
```bash
tree ~/.gnupg/
/Users/ryan/.gnupg/
|-- S.gpg-agent # socket file
@@ -185,28 +201,41 @@ The generated keys are stored in `~/.gnupg` by default, the functions of each fi
4 directories, 12 files
```
The functions of most files are quite clear at a glance, but the `trustdb.gpg` in them is a bit difficult to understand. Here are the details: <https://www.gnupg.org/gph/en/manual/x334.html>
The functions of most files are quite clear at a glance, but the `trustdb.gpg` in them is a bit
difficult to understand. Here are the details: <https://www.gnupg.org/gph/en/manual/x334.html>
Home Manager will manage all the things in `~/.gnupg/` EXCEPT `~/.gnupg/openpgp-revocs.d/` and `~/.gnupg/private-keys-v1.d/`, which is expected.
Home Manager will manage all the things in `~/.gnupg/` EXCEPT `~/.gnupg/openpgp-revocs.d/` and
`~/.gnupg/private-keys-v1.d/`, which is expected.
### 3. Sub Key Generation & Best Practice
In PGP, every keys has a **usage flag** to indicate its usage:
- `C` means this key can be used to **Certify** other keys, which means this key can be used to **create/delete/revoke/modify** other keys.
- `C` means this key can be used to **Certify** other keys, which means this key can be used to
**create/delete/revoke/modify** other keys.
- `S` means this key can be used to **Sign** data.
- `E` means this key can be used to **Encrypt** data.
- `A` means this key can be used to **Authenticate** data with various non-GnuPG programs. The key can be used as e.g. an **SSH key**.
- `E` means this key can be used to **Encrypt** data.
- `A` means this key can be used to **Authenticate** data with various non-GnuPG programs. The key
can be used as e.g. an **SSH key**.
The **best practice** is:
1. Generate a primary key with strong cryptography arguments(such as ECC + Curve 25519).
2. Then generate 3 sub keys with `E`, `S` and `A` usage flag respectively.
3. **The Primary Key is extremely important**, Backup the primary key to somewhere absolutely safe(such as two encryptd USB drivers, keep them in different places), and then **delete it from your computer immediately**.
4. The sub key is also important, but you can generate a new one and replace it easily. You can backup it to somewhere else, and import it to another machine to use your keypair.
5. Backup your Primary key's revocation certificate to somewhere safe, it's the last way to rescure your safety if your primary key is compromised!
1. It's a big problem if your revocation certificate is compromised, but not the bigest one. because it's only used to revoke your keypair, your data is still safe. But you should generate a new keypair and revoke the old one immediately.
1. It will be a big problem if your primary key is compromised, and you don't have a revocation certificate to revoke it. But since OpenPGP do not have a good way to distribute revocation certificate, even you have a revocation certificate, it's still hard to distribute it to others...
3. **The Primary Key is extremely important**, Backup the primary key to somewhere absolutely
safe(such as two encryptd USB drivers, keep them in different places), and then **delete it from
your computer immediately**.
4. The sub key is also important, but you can generate a new one and replace it easily. You can
backup it to somewhere else, and import it to another machine to use your keypair.
5. Backup your Primary key's revocation certificate to somewhere safe, it's the last way to rescure
your safety if your primary key is compromised!
6. It's a big problem if your revocation certificate is compromised, but not the bigest one. because
it's only used to revoke your keypair, your data is still safe. But you should generate a new
keypair and revoke the old one immediately.
7. It will be a big problem if your primary key is compromised, and you don't have a revocation
certificate to revoke it. But since OpenPGP do not have a good way to distribute revocation
certificate, even you have a revocation certificate, it's still hard to distribute it to
others...
To keep your keypair safe, you should backup your keypair according to the following steps.
@@ -216,7 +245,7 @@ Now let's add the sub keys to the keypair we generated above:
> GnuPG will ask you to input your passphrase to unlock your primary key.
``` bash
```bash
gpg --expert --edit-key ryan4yin@linux.com
gpg (GnuPG) 2.4.1; Copyright (C) 2023 g10 Code GmbH
This is free software: you are free to change and redistribute it.
@@ -380,7 +409,7 @@ ssb ed25519 2024-01-09 [A] [expires: 2034-01-04]
gpg --list-public-keys
...
```
### 4. Backup & Restore
Export Public Keys(Both Primary Key & Sub Keys):
@@ -393,10 +422,12 @@ nix run nixpkgs#pgpdump ryan4yin-gpg-keys.pub
Export Primary Key(The exported key is still encrypted by your passphrase):
> the `!` at the end of the key ID is to force GnuPG to export only the specified key, not the subkeys.
> the `!` at the end of the key ID is to force GnuPG to export only the specified key, not the
> subkeys.
> GnuPG will ask you to input your passphrase to unlock your keypair,
> because GnuPG need to convert the secret key's format from its internal protection format to the one specified by the OpenPGP protocol.
> GnuPG will ask you to input your passphrase to unlock your keypair, because GnuPG need to convert
> the secret key's format from its internal protection format to the one specified by the OpenPGP
> protocol.
```bash
# replace the key ID with your own sec key's ID
@@ -416,16 +447,20 @@ Old: Secret Key Packet(tag 5)(134 bytes)
Hash alg - SHA1(hash 2)
Salt - 8c 78 58 c0 87 83 8c 2c
Count - 65011712(coded count 255)
IV - xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx
IV - xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx
Encrypted EdDSA x
Encrypted SHA1 hash
...
```
As [Predictable, Passphrase-Derived PGP Keys][Predictable, Passphrase-Derived PGP Keys] says, we'll find that gpg ignored the `--s2k-count` option we specified when generating the keypair, and the `--s2k` related options we specified in `~/.gnupg/gpg.conf`,
the exported primary key is protectd by `SHA1` and `AES128`, which is not secure enough!
As [Predictable, Passphrase-Derived PGP Keys][Predictable, Passphrase-Derived PGP Keys] says, we'll
find that gpg ignored the `--s2k-count` option we specified when generating the keypair, and the
`--s2k` related options we specified in `~/.gnupg/gpg.conf`, the exported primary key is protectd by
`SHA1` and `AES128`, which is not secure enough!
So to increase the security of the exported primary key, we need to encrypt it again with a stronger algorithm, I choose `age` here(which use `scrypt` to encrypt the file key with a provided passphrase):
So to increase the security of the exported primary key, we need to encrypt it again with a stronger
algorithm, I choose `age` here(which use `scrypt` to encrypt the file key with a provided
passphrase):
```bash
# for simplicity, use the same passphrase as your gpg keypair here
@@ -446,11 +481,14 @@ age --passphrase -o ryan4yin-gpg-subkeys.priv.age ryan4yin-gpg-subkeys.priv
rm ryan4yin-gpg-subkeys.priv
```
Your can import the exported Private Key via `gpg --import <keyfile>` to restore it, but you need to decrypt it via age first.
Your can import the exported Private Key via `gpg --import <keyfile>` to restore it, but you need to
decrypt it via age first.
As for Public Keys, please import your publicKeys via Home Manager's `programs.gpg.publicKeys` option, DO NOT import it manually(via `gpg --import <keyfile>`).
As for Public Keys, please import your publicKeys via Home Manager's `programs.gpg.publicKeys`
option, DO NOT import it manually(via `gpg --import <keyfile>`).
To ensure security, delete the master key and revoke the certificate immediately after the backup is completed:
To ensure security, delete the master key and revoke the certificate immediately after the backup is
completed:
```bash
# delete the primary key and all its sub keys
@@ -522,7 +560,8 @@ gpg --decrypt <file>
gpg -d <file>
```
If you just want to encrypt/decrypt a file quickly, you can use `age` with a passphrase, `gpg` can also do this, but it's not recommended(as age(scrypt)'s more secure):
If you just want to encrypt/decrypt a file quickly, you can use `age` with a passphrase, `gpg` can
also do this, but it's not recommended(as age(scrypt)'s more secure):
```bash
# Encrypt a file via symmetric encryption(AES256), and output cleartext.
@@ -538,27 +577,41 @@ gpg -d <file>
### 7. Public Key Exchange & Revocation
In the case of many users, it is very difficult to exchange public keys securely and reliably with each other.
In the Web world, There is a **Chain of Trust**** to resolve this problem:
In the case of many users, it is very difficult to exchange public keys securely and reliably with
each other. In the Web world, There is a **Chain of Trust\*\*** to resolve this problem:
- A Certificate Authority(CA) is responsible to verify & sign all the certificate signing request.
- Web Server can safely transmit its Web Certificate to the client via TLS protocol.
- Client can verify the recevied Web Certificate via the CA's root certificate(which is built in Browser/OS).
- Client can verify the received Web Certificate via the CA's root certificate(which is built in
Browser/OS).
But in OpenPGP:
- There is key servers to distribute(exchange) public keys, but it **do not verify the identity of the key owner**, and any uploaded data is **not allowed to be deleted**. Which make it **insecure and dangerous**.
- There is key servers to distribute(exchange) public keys, but it **do not verify the identity of
the key owner**, and any uploaded data is **not allowed to be deleted**. Which make it **insecure
and dangerous**.
- Why key server is dangerous?
- Many PGP novices follow various tutorials to upload various key with personal privacy (such as real names) to the public key server, and then find that they can't delete them, which is very embarrassing.
- Anyone can upload a key to the key server, and claim that it is the key of a certain person(such as Linus), which is very insecure.
- Many PGP novices follow various tutorials to upload various key with personal privacy (such as
real names) to the public key server, and then find that they can't delete them, which is very
embarrassing.
- Anyone can upload a key to the key server, and claim that it is the key of a certain
person(such as Linus), which is very insecure.
- **key server** is not recommend to use.
- GnuPG will generate revocation certificate when generating keypair(`~/.gnupg/private-keys-v1.d/<Key-ID.rev>`), anyone can import this certificate to revoke the keypair. But OpenPGP standard **DO NOT provide a way to distribute this certificate to others**.
- GnuPG will generate revocation certificate when generating
keypair(`~/.gnupg/private-keys-v1.d/<Key-ID.rev>`), anyone can import this certificate to revoke
the keypair. But OpenPGP standard **DO NOT provide a way to distribute this certificate to
others**.
- Not to mention some key status query protocol like OCSP in Web PKI.
- Users has to pulish their revocation certificate to their blog, github profile or somewhere else, and others has to check it and run `gpg --import <revocation-certificate>` to revoke the keypair manually.
- Users has to pulish their revocation certificate to their blog, github profile or somewhere
else, and others has to check it and run `gpg --import <revocation-certificate>` to revoke the
keypair manually.
In summary, **there is no good way to distribute public keys and revoke them in OpenPGP**, which is a big problem.
In summary, **there is no good way to distribute public keys and revoke them in OpenPGP**, which is
a big problem.
Currently, You have to distribute your public key or revocation certificate via your blog, github profile, or somewhere else, and others has to check it and run `gpg --import` to import your public key or revocation certificate manually.
Currently, You have to distribute your public key or revocation certificate via your blog, github
profile, or somewhere else, and others has to check it and run `gpg --import` to import your public
key or revocation certificate manually.
Anyway, let's try to revoke a keypair:
@@ -615,7 +668,8 @@ STuJCp+gru6OtbTCu8Y2LugQeDh7UicM7Ak=
-----END PGP PUBLIC KEY BLOCK-----
```
As the revocation certificate says, we need to remove the first colon(`:`) before the 5 dashes(`-----BEGIN PGP PUBLIC KEY BLOCK-----`), then import it:
As the revocation certificate says, we need to remove the first colon(`:`) before the 5
dashes(`-----BEGIN PGP PUBLIC KEY BLOCK-----`), then import it:
```bash
gpg --import gpg-test-revoke.rev
@@ -646,7 +700,8 @@ gpg: 9E78E897B6490D6B: skipped: Unusable public key
gpg: README.md: encryption failed: Unusable public key
```
But if you delete the `trustdb.gpg` and `pubring.kbx`, then import the revoked public key again, it will be valid and usable again... which is very dangerous.
But if you delete the `trustdb.gpg` and `pubring.kbx`, then import the revoked public key again, it
will be valid and usable again... which is very dangerous.
## References
@@ -654,7 +709,8 @@ But if you delete the `trustdb.gpg` and `pubring.kbx`, then import the revoked p
- [Predictable, Passphrase-Derived PGP Keys][Predictable, Passphrase-Derived PGP Keys]
- [OpenPGP - The almost perfect key pair][OpenPGP - The almost perfect key pair]
[2021年用更现代的方法使用PGP]: https://ulyc.github.io/2021/01/13/2021%E5%B9%B4-%E7%94%A8%E6%9B%B4%E7%8E%B0%E4%BB%A3%E7%9A%84%E6%96%B9%E6%B3%95%E4%BD%BF%E7%94%A8PGP-%E4%B8%8A/
[2021年用更现代的方法使用PGP]:
https://ulyc.github.io/2021/01/13/2021%E5%B9%B4-%E7%94%A8%E6%9B%B4%E7%8E%B0%E4%BB%A3%E7%9A%84%E6%96%B9%E6%B3%95%E4%BD%BF%E7%94%A8PGP-%E4%B8%8A/
[Predictable, Passphrase-Derived PGP Keys]: https://nullprogram.com/blog/2019/07/10/
[OpenPGP - The almost perfect key pair]: https://blog.eleven-labs.com/en/openpgp-almost-perfect-key-pair-part-1/
[OpenPGP - The almost perfect key pair]:
https://blog.eleven-labs.com/en/openpgp-almost-perfect-key-pair-part-1/

View File

@@ -16,32 +16,31 @@ To ensure security, we should change the GPG key every two or three years. Here
3. Update `./default.nix` to use the new GPG sub keys.
4. Check which Key `pass` currently uses:
```bash
cd ~/.local/share/password-store/
# check which key is used by pass
cat .gpg-id
# check which key is really used to encrypt the password
gpg --list-packets path/to/any/password.gpg
```
4. Change the key used by `pass`:
```bash
# change the key used by pass, see `man pass` for more details
# you will be asked to enter the password of both the new and old keys
# then pass will re-encrypt all the passwords with the new key
pass init <new-key-id>
```
5. Check if the key is changed:
```bash
# check which key is used by pass
cat .gpg-id
# check which key is really used to encrypt the password
gpg --list-packets path/to/any/password.gpg
```
6. Delete the old GPG key pair:
```bash
# delete the old key pair
gpg --delete-secret-keys <old-key-id>
gpg --delete-keys <old-key-id>
```
```bash
cd ~/.local/share/password-store/
# check which key is used by pass
cat .gpg-id
# check which key is really used to encrypt the password
gpg --list-packets path/to/any/password.gpg
```
5. Change the key used by `pass`:
```bash
# change the key used by pass, see `man pass` for more details
# you will be asked to enter the password of both the new and old keys
# then pass will re-encrypt all the passwords with the new key
pass init <new-key-id>
```
6. Check if the key is changed:
```bash
# check which key is used by pass
cat .gpg-id
# check which key is really used to encrypt the password
gpg --list-packets path/to/any/password.gpg
```
7. Delete the old GPG key pair:
```bash
# delete the old key pair
gpg --delete-secret-keys <old-key-id>
gpg --delete-keys <old-key-id>
```

View File

@@ -1,32 +1,39 @@
# Zellij - A workspace lives in your terminal
Zellij is a terminal workspace with batteries included.
At its core, it is a terminal multiplexer (similar to tmux and screen), but this is merely its infrastructure layer.
Zellij is a terminal workspace with batteries included. At its core, it is a terminal multiplexer
(similar to tmux and screen), but this is merely its infrastructure layer.
Zellij is very user-friendly and easy to use, with a step-by-step hint system that will help you get to know the keybindings, which is very like the Neovim or helix.
Zellij is very user-friendly and easy to use, with a step-by-step hint system that will help you get
to know the keybindings, which is very like the Neovim or helix.
> By contrast, tmux's key design is counterintuitive, there is no prompt system, and the plug-in performance is rubbish. It's really a pain to use.
> tmux's inital release was in 2007, it's too old, I would recommend any users that do not have a experience with multiplexer to use zellij instead of tmux.
> By contrast, tmux's key design is counterintuitive, there is no prompt system, and the plug-in
> performance is rubbish. It's really a pain to use. tmux's initial release was in 2007, it's too
> old, I would recommend any users that do not have a experience with multiplexer to use zellij
> instead of tmux.
## Why use zellij as the detault terminal environment?
## Why use zellij as the default terminal environment?
By auto start zellij on shell login, and exit the shell session on zellij exit, we can use zellij as the default terminal environment.
By auto start zellij on shell login, and exit the shell session on zellij exit, we can use zellij as
the default terminal environment.
By this way, We will only use the most basic features of the terminal emulator(kitty/alacritty/wezterm/...),
while most of the functions of terminal are provided by zellij.
Thus we can easily switch to any terminal emulator without losing any key functions,
and do not need to take care of the differences between different terminal emulators.
By this way, We will only use the most basic features of the terminal
emulator(kitty/alacritty/wezterm/...), while most of the functions of terminal are provided by
zellij. Thus we can easily switch to any terminal emulator without losing any key functions, and do
not need to take care of the differences between different terminal emulators.
And Zellij can be used not only locally, but also on any remote server, which is very convenient. Learn once and use everywhere!
And Zellij can be used not only locally, but also on any remote server, which is very convenient.
Learn once and use everywhere!
> Yeah, you didn't misread it, zellij is very suitable for not only remotely, but also locally!
Some features such as search/copy/scrollback in different terminal emulators are implemented in different ways, and has different user experience.
For example, Wezterm's default search function is very basic, and it's not easy to use. Kitty's scrollback search/copy is really tricky to use.
As for some Editor such as Neovim, its intergrated terminal is really useful, but zellij is more powerful and useful than it, and more stable!
Zellij overcomes these problems, and provides a unified user experience for all terminal emulators!
Some features such as search/copy/scrollback in different terminal emulators are implemented in
different ways, and has different user experience. For example, Wezterm's default search function is
very basic, and it's not easy to use. Kitty's scrollback search/copy is really tricky to use. As for
some Editor such as Neovim, its integrated terminal is really useful, but zellij is more powerful
and useful than it, and more stable! Zellij overcomes these problems, and provides a unified user
experience for all terminal emulators!
Teminal emulators should only be responsible for displaying characters.
Terminal emulators should only be responsible for displaying characters.
## Passthrough mode(Lock Mode)
@@ -34,6 +41,7 @@ Teminal emulators should only be responsible for displaying characters.
It's extremely useful when you want to:
1. Use zellij locally for daily work, and use a remote zellij via ssh to do some work on the remote server.
1. To avoid the key conflicts between zellij and the program running in the terminal, such as vim, tmux, etc.
1. Use zellij locally for daily work, and use a remote zellij via ssh to do some work on the remote
server.
1. To avoid the key conflicts between zellij and the program running in the terminal, such as vim,
tmux, etc.

View File

@@ -4,4 +4,3 @@
2. `shell.nix`: shell related.
3. `rime-squirrel.nix`: [rime-squirrel](https://github.com/rime/squirrel)'s configuration.
4. `default.nix`: the entrypoint of darwin's configuration, it import all the submodules above.

View File

@@ -2,7 +2,9 @@
1. `base`: The base module that is suitable for any NixOS environment.
2. `desktop`: Configuration for desktop environments, such as Hyprland, I3, etc.
6. `server.nix`: Configuration which is suitable for both servers and desktops. It import only `base` as its submodule.
1. used by all my nixos servers.
7. `desktop.nix`: the entrypoint of desktop's configuration, it import both `base` and `desktop` as its submodules.
1. used by all my nixos desktops.
3. `server.nix`: Configuration which is suitable for both servers and desktops. It import only
`base` as its submodule.
1. used by all my nixos servers.
4. `desktop.nix`: the entrypoint of desktop's configuration, it import both `base` and `desktop` as
its submodules.
1. used by all my nixos desktops.

View File

@@ -1,16 +1,18 @@
# Desktop Related
3. `base`: all common configurations for all desktops.
4. `hyprland`: Hyprland's configuration.
5. `i3`: i3's configuration.
## Why install I3/Hyprland in Home Manager instead of a NixOS Module?
1. I3 & Hyprland's configuration file is located in `~/.config`, which can be easily managed by Home Manager.
2. I have many user-specific systemd servcies, such gammastep, wallpaper-switcher, etc. Which can be easily managed by Home Manager, but if we add i3/hyprland in a NixOS Module, those user-level services may failed to start automatically. With i3/hyprland in a Home Manager Module, we can control their systemd service's dependent order more easily, so we can avoid issues like this.
1. I3 & Hyprland's configuration file is located in `~/.config`, which can be easily managed by Home
Manager.
2. I have many user-specific systemd services, such gammastep, wallpaper-switcher, etc. Which can be
easily managed by Home Manager, but if we add i3/hyprland in a NixOS Module, those user-level
services may failed to start automatically. With i3/hyprland in a Home Manager Module, we can
control their systemd service's dependent order more easily, so we can avoid issues like this.
3. By install packages as less as possible in NixOS Module, we can:
1. Make the NixOS system more secure and stable.
2. Make this flake more portable to other non-NixOS systems, as home-manager can be installed on any Linux system.
1. Make the NixOS system more secure and stable.
2. Make this flake more portable to other non-NixOS systems, as home-manager can be installed on
any Linux system.

View File

@@ -2,15 +2,8 @@
"position": "top",
"layer": "top",
"modules-left": [
"custom/launcher",
"temperature",
"backlight",
"hyprland/workspaces"
],
"modules-center": [
"custom/playerctl"
],
"modules-left": ["custom/launcher", "temperature", "backlight", "hyprland/workspaces"],
"modules-center": ["custom/playerctl"],
"modules-right": [
"mpd",
"pulseaudio",
@@ -21,7 +14,7 @@
"clock",
"idle_inhibitor",
"custom/powermenu",
"tray"
"tray",
],
"hyprland/workspaces": {
"format": "{icon}",
@@ -38,8 +31,8 @@
"9": "",
"10": "",
"focused": "",
"default": ""
}
"default": "",
},
},
"clock": {
@@ -48,137 +41,123 @@
"rotate": 0,
"tooltip-format": "<big>{:%B %Y}</big>\n<tt><small>{calendar}</small></tt>",
"format": " {:%H:%M}",
"format-alt": " {:%a %b %d, %G}"
"format-alt": " {:%a %b %d, %G}",
},
"cpu": {
"format": "\udb80\udf5b {usage}%",
"interval": 1,
"on-click-middle": "kitty btop",
"on-click-right": "kitty btop"
"on-click-right": "kitty btop",
},
"custom/launcher": {
"format": "\uf313 ",
"on-click": "$HOME/.config/hypr/scripts/menu",
"on-click-middle": "exec default_wall",
"on-click-right": "exec wallpaper_random",
"tooltip": false
"tooltip": false,
},
"custom/powermenu": {
"format": "\uf011",
"on-click": "$HOME/.config/hypr/scripts/wlogout",
"tooltip": false
"tooltip": false,
},
"idle_inhibitor": {
"format": "{icon}",
"format-icons": {
"activated": "\uf06e",
"deactivated": "\uf070"
"deactivated": "\uf070",
},
"tooltip": false
"tooltip": false,
},
"memory": {
"format": "\udb83\udee0 {percentage}%",
"interval": 1,
"states": {
"warning": 85
}
"warning": 85,
},
},
"mpd": {
"interval": 2,
"unknown-tag": "N/A",
"format": "{stateIcon} {artist} - {title}",
"format-disconnected": " Disconnected",
"format-paused": "{stateIcon} {artist} - {title}",
"format-stopped": "Stopped ",
"state-icons": {
"paused": "",
"playing": ""
},
"tooltip-format": "MPD (connected)",
"tooltip-format-disconnected": "MPD (disconnected)",
// Commands to execute on events
"on-click": "mpc toggle",
"on-click-middle": "mpc prev",
"on-click-right": "mpc next",
"on-update": "",
"on-scroll-up": "mpc seek +00:00:01",
"on-scroll-down": "mpc seek -00:00:01",
"smooth-scrolling-threshold": 1
"interval": 2,
"unknown-tag": "N/A",
"format": "{stateIcon} {artist} - {title}",
"format-disconnected": " Disconnected",
"format-paused": "{stateIcon} {artist} - {title}",
"format-stopped": "Stopped ",
"state-icons": {
"paused": "",
"playing": "",
},
"tooltip-format": "MPD (connected)",
"tooltip-format-disconnected": "MPD (disconnected)",
// Commands to execute on events
"on-click": "mpc toggle",
"on-click-middle": "mpc prev",
"on-click-right": "mpc next",
"on-update": "",
"on-scroll-up": "mpc seek +00:00:01",
"on-scroll-down": "mpc seek -00:00:01",
"smooth-scrolling-threshold": 1,
},
"custom/playerctl": {
"format": "{icon} <span>{}</span>",
"return-type": "json",
"max-length": 55,
"exec": "playerctl -a metadata --format '{\"text\": \" {{markup_escape(title)}}\", \"tooltip\": \"{{playerName}} : {{markup_escape(title)}}\", \"alt\": \"{{status}}\", \"class\": \"{{status}}\"}' -F",
"on-click-middle": "playerctl previous",
"on-click": "playerctl play-pause",
"on-click-right": "playerctl next",
"format-icons": {
"Paused": "<span foreground='#6dd9d9'></span>",
"Playing": "<span foreground='#82db97'></span>"
}
"format": "{icon} <span>{}</span>",
"return-type": "json",
"max-length": 55,
"exec": "playerctl -a metadata --format '{\"text\": \" {{markup_escape(title)}}\", \"tooltip\": \"{{playerName}} : {{markup_escape(title)}}\", \"alt\": \"{{status}}\", \"class\": \"{{status}}\"}' -F",
"on-click-middle": "playerctl previous",
"on-click": "playerctl play-pause",
"on-click-right": "playerctl next",
"format-icons": {
"Paused": "<span foreground='#6dd9d9'></span>",
"Playing": "<span foreground='#82db97'></span>",
},
},
"network": {
"interval": 5,
//"interface": "wlan*", // (Optional) To force the use of this interface, set it for netspeed to work
"format-wifi": " {essid}",
"format-ethernet": " {ipaddr}/{cidr}",
"format-linked": " {ifname} (No IP)",
"format-disconnected": "睊 Disconnected",
"format-disabled": "睊 Disabled",
"format-alt": " {bandwidthUpBytes} |  {bandwidthDownBytes}",
"tooltip-format": " {ifname} via {gwaddr}",
"on-click-middle": "nm-connection-editor",
"on-click-right": "kitty nmtui"
"interval": 5,
//"interface": "wlan*", // (Optional) To force the use of this interface, set it for netspeed to work
"format-wifi": " {essid}",
"format-ethernet": " {ipaddr}/{cidr}",
"format-linked": " {ifname} (No IP)",
"format-disconnected": "睊 Disconnected",
"format-disabled": "睊 Disabled",
"format-alt": " {bandwidthUpBytes} |  {bandwidthDownBytes}",
"tooltip-format": " {ifname} via {gwaddr}",
"on-click-middle": "nm-connection-editor",
"on-click-right": "kitty nmtui",
},
"pulseaudio": {
//"format": "{volume}% {icon} {format_source}",
"format": "{icon} {volume}%",
"format-muted": " Mute",
"format-bluetooth": " {volume}% {format_source}",
"format-bluetooth-muted": " Mute",
"format-source": " {volume}%",
"format-source-muted": "",
"format-icons": {
"headphone": "",
"hands-free": "",
"headset": "",
"phone": "",
"portable": "",
"car": "",
"default": [
"",
"",
""
]
},
"scroll-step": 5.0,
// Commands to execute on events
"on-click": "amixer set Master toggle",
"on-click-right": "pavucontrol",
"smooth-scrolling-threshold": 1,
//"format": "{volume}% {icon} {format_source}",
"format": "{icon} {volume}%",
"format-muted": " Mute",
"format-bluetooth": " {volume}% {format_source}",
"format-bluetooth-muted": " Mute",
"format-source": " {volume}%",
"format-source-muted": "",
"format-icons": {
"headphone": "",
"hands-free": "",
"headset": "",
"phone": "",
"portable": "",
"car": "",
"default": ["", "", ""],
},
"scroll-step": 5.0,
// Commands to execute on events
"on-click": "amixer set Master toggle",
"on-click-right": "pavucontrol",
"smooth-scrolling-threshold": 1,
},
"temperature": {
"format": "\uf2c9 {temperatureC}\u00b0C",
"tooltip": false
"tooltip": false,
},
"backlight": {
"format": "{icon} {percent}%",
"format-icons": [
"",
"",
"",
"",
"",
"",
"",
"",
""
]
"format-icons": ["", "", "", "", "", "", "", "", ""],
},
"tray": {
"icon-size": 15,
"spacing": 5
"spacing": 5,
},
"battery": {
"bat": "BAT0",
@@ -186,7 +165,7 @@
"interval": 60,
"states": {
"warning": 30,
"critical": 15
"critical": 15,
},
"max-length": 20,
"format": "{icon} {capacity}%",
@@ -196,12 +175,6 @@
"format-plugged": " {capacity}%",
"format-alt": "{icon} {time}",
"format-full": " {capacity}%",
"format-icons": [
" ",
" ",
" ",
" ",
" "
]
"format-icons": [" ", " ", " ", " ", " "],
},
}

View File

@@ -36,5 +36,3 @@
@define-color pink #f5c2e7;
@define-color flamingo #f2cdcd;
@define-color rosewater #f5e0dc;

View File

@@ -1,52 +1,57 @@
/** ********** Fonts ********** **/
* {
font-family: "JetBrains Mono", "Iosevka Nerd Font", sans-serif;
font-size: 14px;
font-weight: bold;
font-family: "JetBrains Mono", "Iosevka Nerd Font", sans-serif;
font-size: 14px;
font-weight: bold;
}
/** ********** Main Window ********** **/
window {
background-color: #1E1E2E;
background-color: #1e1e2e;
}
/** ********** Buttons ********** **/
button {
background-color: #242434;
color: #FFFFFF;
border: 2px solid #282838;
border-radius: 20px;
background-repeat: no-repeat;
background-position: center;
background-size: 35%;
background-color: #242434;
color: #ffffff;
border: 2px solid #282838;
border-radius: 20px;
background-repeat: no-repeat;
background-position: center;
background-size: 35%;
}
button:focus, button:active, button:hover {
background-color: #89B4FA;
outline-style: none;
button:focus,
button:active,
button:hover {
background-color: #89b4fa;
outline-style: none;
}
/** ********** Icons ********** **/
#lock {
background-image: image(url("icons/lock.png"), url("/usr/share/wlogout/icons/lock.png"));
background-image: image(url("icons/lock.png"), url("/usr/share/wlogout/icons/lock.png"));
}
#logout {
background-image: image(url("icons/logout.png"), url("/usr/share/wlogout/icons/logout.png"));
background-image: image(url("icons/logout.png"), url("/usr/share/wlogout/icons/logout.png"));
}
#suspend {
background-image: image(url("icons/suspend.png"), url("/usr/share/wlogout/icons/suspend.png"));
background-image: image(url("icons/suspend.png"), url("/usr/share/wlogout/icons/suspend.png"));
}
#hibernate {
background-image: image(url("icons/hibernate.png"), url("/usr/share/wlogout/icons/hibernate.png"));
background-image: image(
url("icons/hibernate.png"),
url("/usr/share/wlogout/icons/hibernate.png")
);
}
#shutdown {
background-image: image(url("icons/shutdown.png"), url("/usr/share/wlogout/icons/shutdown.png"));
background-image: image(url("icons/shutdown.png"), url("/usr/share/wlogout/icons/shutdown.png"));
}
#reboot {
background-image: image(url("icons/reboot.png"), url("/usr/share/wlogout/icons/reboot.png"));
background-image: image(url("icons/reboot.png"), url("/usr/share/wlogout/icons/reboot.png"));
}

View File

@@ -1,3 +1,4 @@
# Scripts for I3 Blocks
Mostly copy from [i3blocks-contrib](https://github.com/vivien/i3blocks-contrib), the Official repository for community contributed blocklets.
Mostly copy from [i3blocks-contrib](https://github.com/vivien/i3blocks-contrib), the Official
repository for community contributed blocklets.

View File

@@ -18,7 +18,7 @@ zram0 254:0 0 0B 0 disk
nvme0n1 259:0 0 1.8T 0 disk
├─nvme0n1p1 259:1 0 630M 0 part /boot
└─nvme0n1p2 259:2 0 1.8T 0 part
└─crypted 253:0 0 1.8T 0 crypt /tmp
└─encrypted 253:0 0 1.8T 0 crypt /tmp
/swap
/snapshots
/home/ryan/tmp
@@ -123,7 +123,9 @@ dd bs=512 count=64 iflag=fullblock seek=128 if=$KEYFILE of=$DEVICE
### 2. Partition the SSD & install NixOS via disko
First, follow [UEFI - ryan4yin/nixos-rk3588](https://github.com/ryan4yin/nixos-rk3588/blob/main/UEFI.md) to install UEFI bootloader and boot into NixOS live environment via a USB stick.
First, follow
[UEFI - ryan4yin/nixos-rk3588](https://github.com/ryan4yin/nixos-rk3588/blob/main/UEFI.md) to
install UEFI bootloader and boot into NixOS live environment via a USB stick.
Then, run the following commands:
@@ -145,5 +147,3 @@ cd ~/nix-config
# NOTE: the root password you set here will be discarded when reboot
sudo nixos-install --root /mnt --flake .#rakushun --no-root-password --show-trace --verbose
```

View File

@@ -8,12 +8,9 @@ Related:
- <https://github.com/NixOS/nixos-hardware/tree/master/apple/t2>
- <https://wiki.t2linux.org/distributions/nixos/installation/>
TODOs:
- [ ] Resume from suspend(close the lid) doesn't work
- [ ] Show battery percentage in i3blocks/waybar
- [ ] Touchbar unusable some times
- It works on boot, but after a while it stops working
- It works on boot, but after a while it stops working

View File

@@ -2,7 +2,6 @@
LUKS encrypted SSD for NixOS, on Orange Pi 5.
## Showcases
![](../../_img/2024-03-07_orangepi5_suzu.webp)
@@ -19,7 +18,7 @@ zram0 254:0 0 0B 0 disk
nvme0n1 259:0 0 238.5G 0 disk
├─nvme0n1p1 259:1 0 630M 0 part /boot
└─nvme0n1p2 259:2 0 237.9G 0 part
└─crypted 253:0 0 237.8G 0 crypt /tmp
└─encrypted 253:0 0 237.8G 0 crypt /tmp
/snapshots
/swap
/home/ryan/tmp
@@ -97,7 +96,7 @@ Caches (sum of all):
L3: 3 MiB (1 instance)
```
## How to install NixOS on Orange Pi 5
## How to install NixOS on Orange Pi 5
### 1. Prepare a USB LUKS key
@@ -124,7 +123,9 @@ dd bs=512 count=64 iflag=fullblock seek=128 if=$KEYFILE of=$DEVICE
### 2. Partition the SSD & install NixOS via disko
First, follow [UEFI - ryan4yin/nixos-rk3588](https://github.com/ryan4yin/nixos-rk3588/blob/main/UEFI.md) to install UEFI bootloader and boot into NixOS live environment via a USB stick.
First, follow
[UEFI - ryan4yin/nixos-rk3588](https://github.com/ryan4yin/nixos-rk3588/blob/main/UEFI.md) to
install UEFI bootloader and boot into NixOS live environment via a USB stick.
Then, run the following commands:
@@ -145,5 +146,3 @@ cd ~/nix-config
# NOTE: the root password you set here will be discarded when reboot
sudo nixos-install --root /mnt --flake .#suzu --no-root-password --show-trace --verbose
```

View File

@@ -5,32 +5,42 @@
1. `harmonica`: MacBook Pro 2020 13-inch i5 16G, for personal use.
2. `idols`
1. `ai`: My main computer, with NixOS + I5-13600KF + RTX 4090 GPU, for gaming & daily use.
2. `aquamarine`: My NixOS virtual machine as a router(IPv4 only) with a tranparent proxy to bypass the G|F|W.
3. `ruby`: Another NixOS VM running operation and maintenance related services, such as prometheus, grafana, restic, etc.
4. `kana`: Yet another NixOS VM running some common applications, such as hompage, file browser, torrent downloader, etc.
2. `aquamarine`: My NixOS virtual machine as a router(IPv4 only) with a transparent proxy to
bypass the G|F|W.
3. `ruby`: Another NixOS VM running operation and maintenance related services, such as
prometheus, grafana, restic, etc.
4. `kana`: Yet another NixOS VM running some common applications, such as hompage, file browser,
torrent downloader, etc.
3. Homelab:
1. `tailscale-gw`: A tailscale subnet router(gateway) for accessing my homelab remotely. NixOS VM running on Proxmox.
1. `tailscale-gw`: A tailscale subnet router(gateway) for accessing my homelab remotely. NixOS VM
running on Proxmox.
4. `rolling_girls`: My RISCV64 hosts.
1. `nozomi`: Lichee Pi 4A, TH1520(4xC910@2.0G), 16GB RAM + 32G eMMC + 128G SD Card.
2. `yukina`: Milk-V Mars, JH7110(4xU74@1.5 GHz), 4G RAM + No eMMC + 64G SD Card.
5. `12kingdoms`:
1. `shoukei`: NixOS on Macbook Pro 2020 Intel i5, 13.3-inch, 16G RAM + 512G SSD.
1. `suzu`: Orange Pi 5, RK3588s(4xA76 + 4xA55), GPU(4Cores, Mail-G610), NPU(6Tops@int8), 8G RAM + 256G SSD.
1. `rakushun`: Orange Pi 5 Plus, RK3588(4xA76 + 4xA55), GPU(4Cores, Mail-G610), NPU(6Tops@int8), 16G RAM + 2T SSD.
1. `suzu`: Orange Pi 5, RK3588s(4xA76 + 4xA55), GPU(4Cores, Mail-G610), NPU(6Tops@int8), 8G RAM +
256G SSD.
1. `rakushun`: Orange Pi 5 Plus, RK3588(4xA76 + 4xA55), GPU(4Cores, Mail-G610), NPU(6Tops@int8),
16G RAM + 2T SSD.
6. `k8s`: My Kubernetes Clusters
## How to add a new host
1. Under `hosts/`
1. Create a new folder under `hosts/` with the name of the new host.
2. Create & add the new host's `hardware-configuration.nix` to the new folder, and add the new host's `configuration.nix` to `hosts/<name>/default.nix`.
2. Create & add the new host's `hardware-configuration.nix` to the new folder, and add the new
host's `configuration.nix` to `hosts/<name>/default.nix`.
3. If the new host need to use home-manager, add its custom config into `hosts/<name>/home.nix`.
1. Under `outputs/`
1. Add a new nix file named `outputs/<system-architecture>/src/<name>.nix`.
2. Copy the content from one of the existing similar host, and modify it to fit the new host.
1. Usually, you only need to modify the `name` and `tags` fields.
3. [Optional] Add a new unit test file under `outputs/<system-architecture>/tests/<name>.nix` to test the new host's nix file.
4. [Optional] Add a new integration test file under `outputs/<system-architecture>/integration-tests/<name>.nix` to test whether the new host's nix config can be built and deployed correctly.
3. [Optional] Add a new unit test file under `outputs/<system-architecture>/tests/<name>.nix` to
test the new host's nix file.
4. [Optional] Add a new integration test file under
`outputs/<system-architecture>/integration-tests/<name>.nix` to test whether the new host's
nix config can be built and deployed correctly.
## idols - Oshi no Ko
@@ -44,9 +54,13 @@ My All RISCV64 hosts.
## Distributed Building
I usually run the build command on `Ai` and nix will distribute the build to other NixOS machines, which is convenient and fast.
I usually run the build command on `Ai` and nix will distribute the build to other NixOS machines,
which is convenient and fast.
When building some packages for riscv64 or aarch64, I often have no cache available because of various changes under the hood, so I need to build much more packages than usual, which is one of the reasons why the cluster was originally built, and another reason is distributed building is cool!
When building some packages for riscv64 or aarch64, I often have no cache available because of
various changes under the hood, so I need to build much more packages than usual, which is one of
the reasons why the cluster was originally built, and another reason is distributed building is
cool!
![](/_img/nix-distributed-building.webp)
@@ -56,8 +70,7 @@ When building some packages for riscv64 or aarch64, I often have no cache availa
[Oshi no Ko 【推しの子】 - Wikipedia](https://en.wikipedia.org/wiki/Oshi_no_Ko):
![](/_img/idols-famaily.webp)
![](/_img/idols-ai.webp)
![](/_img/idols-famaily.webp) ![](/_img/idols-ai.webp)
[The Rolling Girls【ローリング☆ガールズ】 - Wikipedia](https://en.wikipedia.org/wiki/The_Rolling_Girls):
@@ -65,7 +78,6 @@ When building some packages for riscv64 or aarch64, I often have no cache availa
[List of Twelve Kingdoms characters](https://en.wikipedia.org/wiki/List_of_Twelve_Kingdoms_characters)
![](/_img/12kingdoms-1.webp)
![](/_img/12kingdoms-Youko-Rakushun.webp)
![](/_img/12kingdoms-1.webp) ![](/_img/12kingdoms-Youko-Rakushun.webp)
[List of Frieren characters](https://en.wikipedia.org/wiki/List_of_Frieren_characters)

View File

@@ -33,14 +33,14 @@ tmpfs tmpfs 100K 0 100K 0% /var/lib/lxd/shmounts
tmpfs tmpfs 100K 0 100K 0% /var/lib/lxd/devlxd
/dev/mapper/crypted-nixos btrfs 1.9T 630G 1.3T 34% /tmp
~
~
lsblk
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS
zram0 253:0 0 15.6G 0 disk [SWAP]
nvme0n1 259:0 0 1.8T 0 disk
nvme0n1 259:0 0 1.8T 0 disk
├─nvme0n1p1 259:2 0 598M 0 part /boot
└─nvme0n1p2 259:3 0 1.8T 0 part
└─crypted-nixos 254:0 0 1.8T 0 crypt /tmp
└─nvme0n1p2 259:3 0 1.8T 0 part
└─encrypted-nixos 254:0 0 1.8T 0 crypt /tmp
/swap/swapfile
/swap
/snapshots

View File

@@ -1,14 +1,15 @@
# Idols - Aquamarine
A router(IPv4 only) with a tranparent proxy to bypass the G|F|W.
A router(IPv4 only) with a transparent proxy to bypass the G|F|W.
NOTE: dae(running on aquamarine) do not provides a http/socks5 proxy server, so a v2ray server is running on [idols_kana](../idols_kana/proxy.nix) to provides a http/socks5 proxy service.
NOTE: dae(running on aquamarine) do not provides a http/socks5 proxy server, so a v2ray server is
running on [idols_kana](../idols_kana/proxy.nix) to provides a http/socks5 proxy service.
## Troubleshooting
### Can not access the global internet
1. Check wether the subscription url is accessible.
1. Check whether the subscription url is accessible.
- If not, then you need to get a new subscription url and update the `dae`'s configuration.
1. Check the `dae` service's log by `journalctl -u dae -n 1000`.
@@ -24,19 +25,24 @@ NOTE: dae(running on aquamarine) do not provides a http/socks5 proxy server, so
1. `ss -tunlp`, check if `dnsmasq` is running and listening on udp port 67.
1. `journalctl -u dnsmasq -n 1000` to check the log of `dnsmasq`.
1. Request a new IP address by disconnect and reconnect one of your devices' wifi.
1. `nix shell nixpkgs#dhcpdump` and then `sudo dhcpdump -i br-lan`, check if the DHCP request is received by `dnsmasq`.
1. `nix shell nixpkgs#dhcpdump` and then `sudo dhcpdump -i br-lan`, check if the DHCP request is
received by `dnsmasq`.
1. The server listens on UDP port number 67, and the client listens on UDP port number 68.
1. DHCP operations fall into four phases:
1. Server **discovery**: The DHCP client broadcasts a DHCPDISCOVER message on the network subnet using the destination address 255.255.255.255 (limited broadcast) or the specific subnet broadcast address (directed broadcast).
1. IP lease **offer**: When a DHCP server receives a DHCPDISCOVER message from a client, which is an IP address lease request, the DHCP server reserves an IP address for the client and makes a lease offer by sending a DHCPOFFER message to the client.
1. IP lease **request**: In response to the DHCP offer, the client replies with a DHCPREQUEST message, broadcast to the server,[a] requesting the offered address.
1. IP lease **acknowledgement**: When the DHCP server receives the DHCPREQUEST message from the client, it sends a DHCPACK packet to the client, which includes the lease duration and any other configuration information that the client might have requested.
1. Server **discovery**: The DHCP client broadcasts a DHCPDISCOVER message on the network
subnet using the destination address 255.255.255.255 (limited broadcast) or the specific
subnet broadcast address (directed broadcast).
1. IP lease **offer**: When a DHCP server receives a DHCPDISCOVER message from a client, which
is an IP address lease request, the DHCP server reserves an IP address for the client and
makes a lease offer by sending a DHCPOFFER message to the client.
1. IP lease **request**: In response to the DHCP offer, the client replies with a DHCPREQUEST
message, broadcast to the server,[a] requesting the offered address.
1. IP lease **acknowledgement**: When the DHCP server receives the DHCPREQUEST message from
the client, it sends a DHCPACK packet to the client, which includes the lease duration and
any other configuration information that the client might have requested.
1. So if you see only `DISCOVER` messages, the dhsmasq is not working properly.
## References
- <https://github.com/ghostbuster91/blogposts/blob/main/router2023-part2/main.md>
- <https://github.com/ghostbuster91/nixos-router>

View File

@@ -2,8 +2,9 @@
Host running some common applications, such as hompage, file browser, torrent downloader, etc.
All the services assumes a reverse proxy to be setup in the front, they are all listening on localhost,
and a caddy service is listening on the local network interface and proxy the requests to the services.
All the services assumes a reverse proxy to be setup in the front, they are all listening on
localhost, and a caddy service is listening on the local network interface and proxy the requests to
the services.
## Services
@@ -13,4 +14,3 @@ and a caddy service is listening on the local network interface and proxy the re
1. uptime-kuma: uptime monitoring
1. alist/filebrower: File browser for local/SMB/Cloud
1. excalidraw/DDTV/owncast/jitsi-meet/...

View File

@@ -1,4 +1,3 @@
# Homepage for my Homelab
> WIP, just a demo for now

View File

@@ -6,4 +6,3 @@
- Github:
- abbr: GH
href: https://github.com/ryan4yin

View File

@@ -4,5 +4,3 @@
# read kubbecofig from $KUBECONFIG or $HOME/.kube/config
# mode: default
mode: disabled

View File

@@ -6,19 +6,19 @@
- PVE-UM560:
icon: si-proxmox
href: https://192.168.5.173:8006/
description: 'CPU: R5-5625U / MEM: 32G / DISK: 512G+4T*2'
description: "CPU: R5-5625U / MEM: 32G / DISK: 512G+4T*2"
siteMonitor: https://192.168.5.173:8006/
- PVE-S500Plus:
icon: si-proxmox
href: https://192.168.5.174:8006/
description: 'CPU: R7-5825U / MEM: 64G / DISK: 1T'
description: "CPU: R7-5825U / MEM: 64G / DISK: 1T"
siteMonitor: https://192.168.5.174:8006/
- PVE-GTR5:
icon: si-proxmox
href: https://192.168.5.172:8006/
description: 'CPU: R9-5900HX / MEM: 64G / DISK: 1T'
description: "CPU: R9-5900HX / MEM: 64G / DISK: 1T"
siteMonitor: https://192.168.5.172:8006/
- Homelab Monitoring:
@@ -26,7 +26,7 @@
icon: si-grafana
href: http://grafana.writefor.fun
description: Data visualised on dashboards
siteMonitor: http://grafana.writefor.fun
siteMonitor: http://grafana.writefor.fun
- Prometheus Dashboard:
icon: si-prometheus
href: http://prometheus.writefor.fun
@@ -44,7 +44,6 @@
href: "http://sftpgo.writefor.fun/web/admin/folders"
description: WebDAV & SFTP server
siteMonitor: http://sftpgo.writefor.fun/
# - Kubernetes Monitoring:
# # TODO: Update this
# - Emby:

View File

@@ -16,9 +16,8 @@ language: zh
# You can then pass provider instead of apiKey in your widget configuration.
providers:
# read api keys from environment variables
openweathermap: {{HOMEPAGE_VAR_WEATHERAPI_APIKEY}}
weatherapi: {{HOMEPAGE_VAR_WEATHERAPI_APIKEY}}
openweathermap: { { HOMEPAGE_VAR_WEATHERAPI_APIKEY } }
weatherapi: { { HOMEPAGE_VAR_WEATHERAPI_APIKEY } }
background:
image: /images/rolling-girls.png
@@ -29,7 +28,7 @@ background:
theme: dark # or light
# Supported colors are:
# Supported colors are:
# slate, gray, zinc, neutral, stone, amber,
# yellow, lime, green, emerald, teal, cyan,
# sky, blue, indigo, violet, purple, fuchsia, pink, rose, red, white
@@ -46,7 +45,7 @@ layout:
tab: First
Group A:
initiallyCollapsed: true # collasped by default
initiallyCollapsed: true # collapsed by default
tab: First
style: row
columns: 4

View File

@@ -11,4 +11,3 @@ Host running operation and maintenance related services:
1. prometheus + alertmanager + grafana + loki: Monitor the metrics/logs of my homelab.
1. restic: Backup my personal data to cloud or NAS.
1. synthing: Sync file between android/macbook/PC and NAS.

View File

@@ -2,7 +2,7 @@ apiVersion: 1
providers:
# <string> an unique provider name. Required
- name: 'Dashboards'
- name: "Dashboards"
# <int> Org id. Default to 1
orgId: 1
# <string> provider type. Default to 'file'

View File

@@ -1,4 +1,4 @@
# Grafana Dashbaords
# Grafana Dashboards
## Homelab
@@ -8,4 +8,3 @@
## Kubernetes
1. https://github.com/dotdc/grafana-dashboards-kubernetes/

View File

@@ -128,11 +128,7 @@
"cacheTimeout": null,
"colorBackground": false,
"colorValue": false,
"colors": [
"#299c46",
"rgba(237, 129, 40, 0.89)",
"#d44a3a"
],
"colors": ["#299c46", "rgba(237, 129, 40, 0.89)", "#d44a3a"],
"datasource": "$datasource",
"decimals": 0,
"format": "short",
@@ -297,7 +293,7 @@
"unit": "s"
},
{
"alias": "Last reload sucessfull",
"alias": "Last reload successful",
"colorMode": "cell",
"colors": [
"rgba(245, 54, 54, 0.9)",
@@ -308,10 +304,7 @@
"decimals": 2,
"mappingType": 1,
"pattern": "Value #C",
"thresholds": [
"0",
"1"
],
"thresholds": ["0", "1"],
"type": "number",
"unit": "short"
},
@@ -363,11 +356,7 @@
"cacheTimeout": null,
"colorBackground": false,
"colorValue": false,
"colors": [
"#299c46",
"rgba(237, 129, 40, 0.89)",
"#d44a3a"
],
"colors": ["#299c46", "rgba(237, 129, 40, 0.89)", "#d44a3a"],
"datasource": "$datasource",
"decimals": 0,
"description": "Number of peers in the Alertmanager cluster.",
@@ -445,11 +434,7 @@
"cacheTimeout": null,
"colorBackground": false,
"colorValue": false,
"colors": [
"#299c46",
"rgba(237, 129, 40, 0.89)",
"#d44a3a"
],
"colors": ["#299c46", "rgba(237, 129, 40, 0.89)", "#d44a3a"],
"datasource": "$datasource",
"description": "Current number of active alerts.",
"format": "none",
@@ -526,11 +511,7 @@
"cacheTimeout": null,
"colorBackground": false,
"colorValue": false,
"colors": [
"#299c46",
"rgba(237, 129, 40, 0.89)",
"#d44a3a"
],
"colors": ["#299c46", "rgba(237, 129, 40, 0.89)", "#d44a3a"],
"datasource": "$datasource",
"description": "Current number of suppressed alerts.",
"format": "none",
@@ -607,11 +588,7 @@
"cacheTimeout": null,
"colorBackground": false,
"colorValue": false,
"colors": [
"#299c46",
"rgba(237, 129, 40, 0.89)",
"#d44a3a"
],
"colors": ["#299c46", "rgba(237, 129, 40, 0.89)", "#d44a3a"],
"datasource": "$datasource",
"description": "Current number of active silences.",
"format": "none",
@@ -2469,7 +2446,7 @@
"expr": "increase(alertmanager_cluster_reconnections_total{instance=~\"$instance\"}[$__interval])",
"format": "time_series",
"intervalFactor": 1,
"legendFormat": "Sucessful reconnections",
"legendFormat": "Successful reconnections",
"refId": "A"
},
{
@@ -2578,7 +2555,7 @@
"expr": "increase(alertmanager_cluster_reconnections_total{instance=~\"$instance\"}[$__interval])",
"format": "time_series",
"intervalFactor": 1,
"legendFormat": "Sucessful reconnections",
"legendFormat": "Successful reconnections",
"refId": "A"
},
{
@@ -2687,7 +2664,7 @@
"expr": "increase(alertmanager_cluster_reconnections_total{instance=~\"$instance\"}[$__interval])",
"format": "time_series",
"intervalFactor": 1,
"legendFormat": "Sucessful reconnections",
"legendFormat": "Successful reconnections",
"refId": "A"
},
{
@@ -2796,7 +2773,7 @@
"expr": "increase(alertmanager_cluster_reconnections_total{instance=~\"$instance\"}[$__interval])",
"format": "time_series",
"intervalFactor": 1,
"legendFormat": "Sucessful reconnections",
"legendFormat": "Successful reconnections",
"refId": "A"
},
{
@@ -10161,15 +10138,11 @@
"format": "time_series",
"groupBy": [
{
"params": [
"$__interval"
],
"params": ["$__interval"],
"type": "time"
},
{
"params": [
"null"
],
"params": ["null"],
"type": "fill"
}
],
@@ -10183,9 +10156,7 @@
"select": [
[
{
"params": [
"value"
],
"params": ["value"],
"type": "field"
},
{
@@ -10305,15 +10276,11 @@
"format": "time_series",
"groupBy": [
{
"params": [
"$__interval"
],
"params": ["$__interval"],
"type": "time"
},
{
"params": [
"null"
],
"params": ["null"],
"type": "fill"
}
],
@@ -10327,9 +10294,7 @@
"select": [
[
{
"params": [
"value"
],
"params": ["value"],
"type": "field"
},
{
@@ -10449,15 +10414,11 @@
"format": "time_series",
"groupBy": [
{
"params": [
"$__interval"
],
"params": ["$__interval"],
"type": "time"
},
{
"params": [
"null"
],
"params": ["null"],
"type": "fill"
}
],
@@ -10471,9 +10432,7 @@
"select": [
[
{
"params": [
"value"
],
"params": ["value"],
"type": "field"
},
{
@@ -10593,15 +10552,11 @@
"format": "time_series",
"groupBy": [
{
"params": [
"$__interval"
],
"params": ["$__interval"],
"type": "time"
},
{
"params": [
"null"
],
"params": ["null"],
"type": "fill"
}
],
@@ -10615,9 +10570,7 @@
"select": [
[
{
"params": [
"value"
],
"params": ["value"],
"type": "field"
},
{
@@ -11131,11 +11084,7 @@
"refresh": "5m",
"schemaVersion": 18,
"style": "dark",
"tags": [
"alertmanager",
"prometheus",
"alerting"
],
"tags": ["alertmanager", "prometheus", "alerting"],
"templating": {
"list": [
{
@@ -11185,32 +11134,11 @@
"to": "now"
},
"timepicker": {
"refresh_intervals": [
"5s",
"10s",
"30s",
"1m",
"5m",
"15m",
"30m",
"1h",
"2h",
"1d"
],
"time_options": [
"5m",
"15m",
"1h",
"6h",
"12h",
"24h",
"2d",
"7d",
"30d"
]
"refresh_intervals": ["5s", "10s", "30s", "1m", "5m", "15m", "30m", "1h", "2h", "1d"],
"time_options": ["5m", "15m", "1h", "6h", "12h", "24h", "2d", "7d", "30d"]
},
"timezone": "",
"title": "Alertmanager",
"uid": "eea-9_sik",
"version": 27
}
}

View File

@@ -131,9 +131,7 @@
"justifyMode": "auto",
"orientation": "auto",
"reduceOptions": {
"calcs": [
"last"
],
"calcs": ["last"],
"fields": "",
"values": false
},
@@ -198,9 +196,7 @@
"justifyMode": "auto",
"orientation": "auto",
"reduceOptions": {
"calcs": [
"last"
],
"calcs": ["last"],
"fields": "",
"values": false
},
@@ -320,9 +316,7 @@
"justifyMode": "auto",
"orientation": "auto",
"reduceOptions": {
"calcs": [
"last"
],
"calcs": ["last"],
"fields": "",
"values": false
},
@@ -441,11 +435,7 @@
"id": 93,
"options": {
"legend": {
"calcs": [
"min",
"max",
"mean"
],
"calcs": ["min", "max", "mean"],
"displayMode": "list",
"placement": "right",
"showLegend": false
@@ -540,11 +530,7 @@
"id": 96,
"options": {
"legend": {
"calcs": [
"min",
"max",
"mean"
],
"calcs": ["min", "max", "mean"],
"displayMode": "list",
"placement": "right",
"showLegend": false
@@ -643,11 +629,7 @@
"id": 74,
"options": {
"legend": {
"calcs": [
"min",
"max",
"mean"
],
"calcs": ["min", "max", "mean"],
"displayMode": "list",
"placement": "right",
"showLegend": false
@@ -794,11 +776,7 @@
"id": 84,
"options": {
"legend": {
"calcs": [
"min",
"max",
"mean"
],
"calcs": ["min", "max", "mean"],
"displayMode": "list",
"placement": "right",
"showLegend": false
@@ -897,11 +875,7 @@
"id": 75,
"options": {
"legend": {
"calcs": [
"min",
"max",
"mean"
],
"calcs": ["min", "max", "mean"],
"displayMode": "list",
"placement": "right",
"showLegend": false
@@ -1000,11 +974,7 @@
"id": 85,
"options": {
"legend": {
"calcs": [
"min",
"max",
"mean"
],
"calcs": ["min", "max", "mean"],
"displayMode": "list",
"placement": "right",
"showLegend": false
@@ -1129,11 +1099,7 @@
"id": 59,
"options": {
"legend": {
"calcs": [
"min",
"max",
"mean"
],
"calcs": ["min", "max", "mean"],
"displayMode": "list",
"placement": "right",
"showLegend": false
@@ -1244,11 +1210,7 @@
"id": 60,
"options": {
"legend": {
"calcs": [
"min",
"max",
"mean"
],
"calcs": ["min", "max", "mean"],
"displayMode": "list",
"placement": "right",
"showLegend": false
@@ -1347,11 +1309,7 @@
"id": 101,
"options": {
"legend": {
"calcs": [
"min",
"max",
"mean"
],
"calcs": ["min", "max", "mean"],
"displayMode": "list",
"placement": "right",
"showLegend": false
@@ -1450,11 +1408,7 @@
"id": 102,
"options": {
"legend": {
"calcs": [
"min",
"max",
"mean"
],
"calcs": ["min", "max", "mean"],
"displayMode": "list",
"placement": "right",
"showLegend": false
@@ -1589,11 +1543,7 @@
"id": 90,
"options": {
"legend": {
"calcs": [
"min",
"max",
"mean"
],
"calcs": ["min", "max", "mean"],
"displayMode": "list",
"placement": "right",
"showLegend": false
@@ -1692,11 +1642,7 @@
"id": 95,
"options": {
"legend": {
"calcs": [
"min",
"max",
"mean"
],
"calcs": ["min", "max", "mean"],
"displayMode": "list",
"placement": "right",
"showLegend": false
@@ -1807,11 +1753,7 @@
"id": 73,
"options": {
"legend": {
"calcs": [
"min",
"max",
"mean"
],
"calcs": ["min", "max", "mean"],
"displayMode": "list",
"placement": "right",
"showLegend": false
@@ -1910,11 +1852,7 @@
"id": 86,
"options": {
"legend": {
"calcs": [
"min",
"max",
"mean"
],
"calcs": ["min", "max", "mean"],
"displayMode": "list",
"placement": "right",
"showLegend": false
@@ -2057,11 +1995,7 @@
"id": 29,
"options": {
"legend": {
"calcs": [
"min",
"max",
"mean"
],
"calcs": ["min", "max", "mean"],
"displayMode": "table",
"placement": "right",
"showLegend": false
@@ -2161,11 +2095,7 @@
"id": 51,
"options": {
"legend": {
"calcs": [
"min",
"max",
"mean"
],
"calcs": ["min", "max", "mean"],
"displayMode": "table",
"placement": "right",
"showLegend": false
@@ -2290,11 +2220,7 @@
"id": 62,
"options": {
"legend": {
"calcs": [
"min",
"max",
"mean"
],
"calcs": ["min", "max", "mean"],
"displayMode": "table",
"placement": "right",
"showLegend": true
@@ -2393,11 +2319,7 @@
"id": 87,
"options": {
"legend": {
"calcs": [
"min",
"max",
"mean"
],
"calcs": ["min", "max", "mean"],
"displayMode": "table",
"placement": "right",
"showLegend": true
@@ -3007,10 +2929,7 @@
"revision": 1,
"schemaVersion": 38,
"style": "dark",
"tags": [
"Kubernetes",
"Prometheus"
],
"tags": ["Kubernetes", "Prometheus"],
"templating": {
"list": [
{
@@ -3147,4 +3066,4 @@
"uid": "k8s_addons_prometheus",
"version": 3,
"weekStart": ""
}
}

View File

@@ -1,47 +1,47 @@
{
"__inputs": [
{
"name": "DS_PROMETHEUS",
"label": "Prometheus",
"description": "",
"type": "datasource",
"pluginId": "prometheus",
"pluginName": "Prometheus"
}
],
"__elements": [],
"__requires": [
{
"type": "grafana",
"id": "grafana",
"name": "Grafana",
"version": "8.5.0"
},
{
"type": "datasource",
"id": "prometheus",
"name": "Prometheus",
"version": "5.0.0"
},
{
"type": "panel",
"id": "timeseries",
"name": "Time series",
"version": ""
},
{
"type": "panel",
"id": "stat",
"name": "Stat",
"version": ""
},
{
"type": "panel",
"id": "table",
"name": "Table",
"version": ""
}
],
"__inputs": [
{
"name": "DS_PROMETHEUS",
"label": "Prometheus",
"description": "",
"type": "datasource",
"pluginId": "prometheus",
"pluginName": "Prometheus"
}
],
"__elements": [],
"__requires": [
{
"type": "grafana",
"id": "grafana",
"name": "Grafana",
"version": "8.5.0"
},
{
"type": "datasource",
"id": "prometheus",
"name": "Prometheus",
"version": "5.0.0"
},
{
"type": "panel",
"id": "timeseries",
"name": "Time series",
"version": ""
},
{
"type": "panel",
"id": "stat",
"name": "Stat",
"version": ""
},
{
"type": "panel",
"id": "table",
"name": "Table",
"version": ""
}
],
"annotations": {
"list": [
{
@@ -129,9 +129,7 @@
"justifyMode": "auto",
"orientation": "auto",
"reduceOptions": {
"calcs": [
"last"
],
"calcs": ["last"],
"fields": "",
"values": false
},
@@ -197,9 +195,7 @@
"justifyMode": "auto",
"orientation": "auto",
"reduceOptions": {
"calcs": [
"last"
],
"calcs": ["last"],
"fields": "",
"values": false
},
@@ -265,9 +261,7 @@
"justifyMode": "auto",
"orientation": "auto",
"reduceOptions": {
"calcs": [
"last"
],
"calcs": ["last"],
"fields": "",
"values": false
},
@@ -333,9 +327,7 @@
"justifyMode": "auto",
"orientation": "auto",
"reduceOptions": {
"calcs": [
"last"
],
"calcs": ["last"],
"fields": "",
"values": false
},
@@ -401,9 +393,7 @@
"justifyMode": "auto",
"orientation": "auto",
"reduceOptions": {
"calcs": [
"last"
],
"calcs": ["last"],
"fields": "",
"values": false
},
@@ -469,9 +459,7 @@
"justifyMode": "auto",
"orientation": "auto",
"reduceOptions": {
"calcs": [
"last"
],
"calcs": ["last"],
"fields": "",
"values": false
},
@@ -863,12 +851,8 @@
"options": {
"footer": {
"enablePagination": true,
"fields": [
"Value"
],
"reducer": [
"sum"
],
"fields": ["Value"],
"reducer": ["sum"],
"show": false
},
"showHeader": true,
@@ -1093,9 +1077,7 @@
"footer": {
"enablePagination": true,
"fields": "",
"reducer": [
"sum"
],
"reducer": ["sum"],
"show": false
},
"showHeader": true,
@@ -1182,9 +1164,7 @@
"operation": "groupby"
},
"Value": {
"aggregations": [
"lastNotNull"
]
"aggregations": ["lastNotNull"]
},
"Vulnerability": {
"aggregations": [],
@@ -1274,9 +1254,7 @@
"justifyMode": "auto",
"orientation": "auto",
"reduceOptions": {
"calcs": [
"last"
],
"calcs": ["last"],
"fields": "",
"values": false
},
@@ -1342,9 +1320,7 @@
"justifyMode": "auto",
"orientation": "auto",
"reduceOptions": {
"calcs": [
"last"
],
"calcs": ["last"],
"fields": "",
"values": false
},
@@ -1410,9 +1386,7 @@
"justifyMode": "auto",
"orientation": "auto",
"reduceOptions": {
"calcs": [
"last"
],
"calcs": ["last"],
"fields": "",
"values": false
},
@@ -1478,9 +1452,7 @@
"justifyMode": "auto",
"orientation": "auto",
"reduceOptions": {
"calcs": [
"last"
],
"calcs": ["last"],
"fields": "",
"values": false
},
@@ -1546,9 +1518,7 @@
"justifyMode": "auto",
"orientation": "auto",
"reduceOptions": {
"calcs": [
"last"
],
"calcs": ["last"],
"fields": "",
"values": false
},
@@ -1882,9 +1852,7 @@
"justifyMode": "auto",
"orientation": "auto",
"reduceOptions": {
"calcs": [
"last"
],
"calcs": ["last"],
"fields": "",
"values": false
},
@@ -1950,9 +1918,7 @@
"justifyMode": "auto",
"orientation": "auto",
"reduceOptions": {
"calcs": [
"last"
],
"calcs": ["last"],
"fields": "",
"values": false
},
@@ -2018,9 +1984,7 @@
"justifyMode": "auto",
"orientation": "auto",
"reduceOptions": {
"calcs": [
"last"
],
"calcs": ["last"],
"fields": "",
"values": false
},
@@ -2086,9 +2050,7 @@
"justifyMode": "auto",
"orientation": "auto",
"reduceOptions": {
"calcs": [
"last"
],
"calcs": ["last"],
"fields": "",
"values": false
},
@@ -2154,9 +2116,7 @@
"justifyMode": "auto",
"orientation": "auto",
"reduceOptions": {
"calcs": [
"last"
],
"calcs": ["last"],
"fields": "",
"values": false
},
@@ -2550,12 +2510,7 @@
"refresh": "30s",
"schemaVersion": 37,
"style": "dark",
"tags": [
"Prometheus",
"Addons",
"Trivy",
"Trivy-operator"
],
"tags": ["Prometheus", "Addons", "Trivy", "Trivy-operator"],
"templating": {
"list": [
{
@@ -2607,12 +2562,8 @@
{
"current": {
"selected": true,
"text": [
"All"
],
"value": [
"$__all"
]
"text": ["All"],
"value": ["$__all"]
},
"datasource": {
"type": "prometheus",

View File

@@ -114,9 +114,7 @@
"justifyMode": "auto",
"orientation": "horizontal",
"reduceOptions": {
"calcs": [
"lastNotNull"
],
"calcs": ["lastNotNull"],
"fields": "",
"values": false
},
@@ -195,9 +193,7 @@
"footer": {
"countRows": false,
"fields": "",
"reducer": [
"sum"
],
"reducer": ["sum"],
"show": false
},
"showHeader": true,
@@ -227,14 +223,7 @@
{
"id": "labelsToFields",
"options": {
"keepLabels": [
"group",
"job",
"removed_release",
"resource",
"version",
"name"
],
"keepLabels": ["group", "job", "removed_release", "resource", "version", "name"],
"mode": "columns"
}
},
@@ -268,9 +257,7 @@
"options": {
"fields": {
"group": {
"aggregations": [
"lastNotNull"
],
"aggregations": ["lastNotNull"],
"operation": "groupby"
},
"job": {
@@ -278,9 +265,7 @@
"operation": "groupby"
},
"namespace": {
"aggregations": [
"lastNotNull"
],
"aggregations": ["lastNotNull"],
"operation": "groupby"
},
"removed_release": {
@@ -288,9 +273,7 @@
"operation": "groupby"
},
"resource": {
"aggregations": [
"lastNotNull"
],
"aggregations": ["lastNotNull"],
"operation": "groupby"
},
"version": {
@@ -1248,10 +1231,7 @@
"refresh": "30s",
"schemaVersion": 38,
"style": "dark",
"tags": [
"Kubernetes",
"Prometheus"
],
"tags": ["Kubernetes", "Prometheus"],
"templating": {
"list": [
{

View File

@@ -114,9 +114,7 @@
"justifyMode": "auto",
"orientation": "vertical",
"reduceOptions": {
"calcs": [
"lastNotNull"
],
"calcs": ["lastNotNull"],
"fields": "",
"values": false
},
@@ -1431,10 +1429,7 @@
],
"refresh": "30s",
"schemaVersion": 38,
"tags": [
"Kubernetes",
"Prometheus"
],
"tags": ["Kubernetes", "Prometheus"],
"templating": {
"list": [
{
@@ -1595,12 +1590,8 @@
{
"current": {
"selected": true,
"text": [
"coredns"
],
"value": [
"coredns"
]
"text": ["coredns"],
"value": ["coredns"]
},
"definition": "label_values(coredns_build_info{cluster=\"$cluster\"},job)",
"hide": 0,

View File

@@ -134,9 +134,7 @@
"namePlacement": "auto",
"orientation": "horizontal",
"reduceOptions": {
"calcs": [
"lastNotNull"
],
"calcs": ["lastNotNull"],
"fields": "",
"values": false
},
@@ -234,9 +232,7 @@
"namePlacement": "auto",
"orientation": "horizontal",
"reduceOptions": {
"calcs": [
"lastNotNull"
],
"calcs": ["lastNotNull"],
"fields": "",
"values": false
},
@@ -323,9 +319,7 @@
"justifyMode": "auto",
"orientation": "auto",
"reduceOptions": {
"calcs": [
"last"
],
"calcs": ["last"],
"fields": "",
"values": false
},
@@ -421,11 +415,7 @@
"id": 52,
"options": {
"legend": {
"calcs": [
"min",
"max",
"mean"
],
"calcs": ["min", "max", "mean"],
"displayMode": "table",
"placement": "right",
"showLegend": true,
@@ -631,9 +621,7 @@
"justifyMode": "auto",
"orientation": "auto",
"reduceOptions": {
"calcs": [
"last"
],
"calcs": ["last"],
"fields": "",
"values": false
},
@@ -694,9 +682,7 @@
"justifyMode": "center",
"orientation": "auto",
"reduceOptions": {
"calcs": [
"lastNotNull"
],
"calcs": ["lastNotNull"],
"fields": "",
"values": false
},
@@ -796,9 +782,7 @@
"justifyMode": "auto",
"orientation": "auto",
"reduceOptions": {
"calcs": [
"lastNotNull"
],
"calcs": ["lastNotNull"],
"fields": "",
"values": false
},
@@ -897,9 +881,7 @@
"justifyMode": "auto",
"orientation": "auto",
"reduceOptions": {
"calcs": [
"last"
],
"calcs": ["last"],
"fields": "",
"values": false
},
@@ -1121,12 +1103,7 @@
"id": 55,
"options": {
"legend": {
"calcs": [
"mean",
"lastNotNull",
"max",
"min"
],
"calcs": ["mean", "lastNotNull", "max", "min"],
"displayMode": "hidden",
"placement": "right",
"showLegend": false
@@ -1229,11 +1206,7 @@
"id": 46,
"options": {
"legend": {
"calcs": [
"min",
"max",
"mean"
],
"calcs": ["min", "max", "mean"],
"displayMode": "table",
"placement": "right",
"showLegend": true,
@@ -1332,11 +1305,7 @@
"id": 50,
"options": {
"legend": {
"calcs": [
"min",
"max",
"mean"
],
"calcs": ["min", "max", "mean"],
"displayMode": "table",
"placement": "right",
"showLegend": true,
@@ -1432,11 +1401,7 @@
"id": 54,
"options": {
"legend": {
"calcs": [
"min",
"max",
"mean"
],
"calcs": ["min", "max", "mean"],
"displayMode": "table",
"placement": "right",
"showLegend": true,
@@ -1531,11 +1496,7 @@
"id": 73,
"options": {
"legend": {
"calcs": [
"min",
"max",
"mean"
],
"calcs": ["min", "max", "mean"],
"displayMode": "table",
"placement": "right",
"showLegend": true,
@@ -1637,11 +1598,7 @@
"id": 82,
"options": {
"legend": {
"calcs": [
"min",
"max",
"mean"
],
"calcs": ["min", "max", "mean"],
"displayMode": "table",
"placement": "right",
"showLegend": true,
@@ -1743,11 +1700,7 @@
"id": 83,
"options": {
"legend": {
"calcs": [
"min",
"max",
"mean"
],
"calcs": ["min", "max", "mean"],
"displayMode": "table",
"placement": "right",
"showLegend": true,
@@ -1857,11 +1810,7 @@
"id": 84,
"options": {
"legend": {
"calcs": [
"min",
"max",
"mean"
],
"calcs": ["min", "max", "mean"],
"displayMode": "table",
"placement": "right",
"showLegend": true,
@@ -1970,11 +1919,7 @@
"id": 85,
"options": {
"legend": {
"calcs": [
"min",
"max",
"mean"
],
"calcs": ["min", "max", "mean"],
"displayMode": "table",
"placement": "right",
"showLegend": true,
@@ -2072,11 +2017,7 @@
"id": 87,
"options": {
"legend": {
"calcs": [
"min",
"max",
"mean"
],
"calcs": ["min", "max", "mean"],
"displayMode": "table",
"placement": "right",
"showLegend": true,
@@ -2174,11 +2115,7 @@
"id": 88,
"options": {
"legend": {
"calcs": [
"min",
"max",
"mean"
],
"calcs": ["min", "max", "mean"],
"displayMode": "table",
"placement": "right",
"showLegend": true,
@@ -2880,10 +2817,7 @@
],
"refresh": "30s",
"schemaVersion": 39,
"tags": [
"Kubernetes",
"Prometheus"
],
"tags": ["Kubernetes", "Prometheus"],
"templating": {
"list": [
{

View File

@@ -133,9 +133,7 @@
"minVizWidth": 75,
"orientation": "auto",
"reduceOptions": {
"calcs": [
"lastNotNull"
],
"calcs": ["lastNotNull"],
"fields": "",
"values": false
},
@@ -209,9 +207,7 @@
"minVizWidth": 75,
"orientation": "auto",
"reduceOptions": {
"calcs": [
"lastNotNull"
],
"calcs": ["lastNotNull"],
"fields": "",
"values": false
},
@@ -307,11 +303,7 @@
"id": 32,
"options": {
"legend": {
"calcs": [
"min",
"max",
"mean"
],
"calcs": ["min", "max", "mean"],
"displayMode": "table",
"placement": "right",
"showLegend": true,
@@ -475,9 +467,7 @@
"justifyMode": "center",
"orientation": "auto",
"reduceOptions": {
"calcs": [
"lastNotNull"
],
"calcs": ["lastNotNull"],
"fields": "",
"values": false
},
@@ -577,9 +567,7 @@
"justifyMode": "auto",
"orientation": "auto",
"reduceOptions": {
"calcs": [
"lastNotNull"
],
"calcs": ["lastNotNull"],
"fields": "",
"values": false
},
@@ -931,11 +919,7 @@
"id": 68,
"options": {
"legend": {
"calcs": [
"min",
"max",
"mean"
],
"calcs": ["min", "max", "mean"],
"displayMode": "table",
"placement": "right",
"showLegend": true,
@@ -1047,11 +1031,7 @@
"id": 70,
"options": {
"legend": {
"calcs": [
"min",
"max",
"mean"
],
"calcs": ["min", "max", "mean"],
"displayMode": "table",
"placement": "right",
"showLegend": true,
@@ -1162,11 +1142,7 @@
"id": 72,
"options": {
"legend": {
"calcs": [
"min",
"max",
"mean"
],
"calcs": ["min", "max", "mean"],
"displayMode": "table",
"placement": "right",
"showLegend": true,
@@ -1266,11 +1242,7 @@
"id": 74,
"options": {
"legend": {
"calcs": [
"min",
"max",
"mean"
],
"calcs": ["min", "max", "mean"],
"displayMode": "table",
"placement": "right",
"showLegend": true,
@@ -1370,11 +1342,7 @@
"id": 75,
"options": {
"legend": {
"calcs": [
"min",
"max",
"mean"
],
"calcs": ["min", "max", "mean"],
"displayMode": "table",
"placement": "right",
"showLegend": true,
@@ -2154,10 +2122,7 @@
],
"refresh": "30s",
"schemaVersion": 39,
"tags": [
"Kubernetes",
"Prometheus"
],
"tags": ["Kubernetes", "Prometheus"],
"templating": {
"list": [
{

View File

@@ -139,9 +139,7 @@
"minVizWidth": 75,
"orientation": "auto",
"reduceOptions": {
"calcs": [
"lastNotNull"
],
"calcs": ["lastNotNull"],
"fields": "",
"values": false
},
@@ -213,9 +211,7 @@
"minVizWidth": 75,
"orientation": "auto",
"reduceOptions": {
"calcs": [
"lastNotNull"
],
"calcs": ["lastNotNull"],
"fields": "",
"values": false
},
@@ -277,9 +273,7 @@
"justifyMode": "auto",
"orientation": "auto",
"reduceOptions": {
"calcs": [
"lastNotNull"
],
"calcs": ["lastNotNull"],
"fields": "",
"values": false
},
@@ -420,9 +414,7 @@
"footer": {
"countRows": false,
"fields": "",
"reducer": [
"sum"
],
"reducer": ["sum"],
"show": false
},
"showHeader": true,
@@ -506,9 +498,7 @@
"operation": "groupby"
},
"namespace": {
"aggregations": [
"last"
],
"aggregations": ["last"],
"operation": "groupby"
},
"pod": {
@@ -566,9 +556,7 @@
"justifyMode": "auto",
"orientation": "auto",
"reduceOptions": {
"calcs": [
"lastNotNull"
],
"calcs": ["lastNotNull"],
"fields": "",
"values": false
},
@@ -631,9 +619,7 @@
"justifyMode": "auto",
"orientation": "auto",
"reduceOptions": {
"calcs": [
"lastNotNull"
],
"calcs": ["lastNotNull"],
"fields": "",
"values": false
},
@@ -695,9 +681,7 @@
"justifyMode": "auto",
"orientation": "auto",
"reduceOptions": {
"calcs": [
"lastNotNull"
],
"calcs": ["lastNotNull"],
"fields": "",
"values": false
},
@@ -760,9 +744,7 @@
"justifyMode": "auto",
"orientation": "auto",
"reduceOptions": {
"calcs": [
"lastNotNull"
],
"calcs": ["lastNotNull"],
"fields": "",
"values": false
},
@@ -833,9 +815,7 @@
"justifyMode": "auto",
"orientation": "auto",
"reduceOptions": {
"calcs": [
"lastNotNull"
],
"calcs": ["lastNotNull"],
"fields": "",
"values": false
},
@@ -1416,11 +1396,7 @@
"id": 66,
"options": {
"legend": {
"calcs": [
"min",
"max",
"mean"
],
"calcs": ["min", "max", "mean"],
"displayMode": "table",
"placement": "right",
"showLegend": true,
@@ -2795,9 +2771,7 @@
"footer": {
"countRows": false,
"fields": "",
"reducer": [
"sum"
],
"reducer": ["sum"],
"show": false
},
"showHeader": true,
@@ -2839,21 +2813,15 @@
"options": {
"fields": {
"Value": {
"aggregations": [
"lastNotNull"
],
"aggregations": ["lastNotNull"],
"operation": "aggregate"
},
"Value #A": {
"aggregations": [
"lastNotNull"
],
"aggregations": ["lastNotNull"],
"operation": "aggregate"
},
"Value #B": {
"aggregations": [
"lastNotNull"
],
"aggregations": ["lastNotNull"],
"operation": "aggregate"
},
"persistentvolumeclaim": {
@@ -3790,10 +3758,7 @@
],
"refresh": "30s",
"schemaVersion": 39,
"tags": [
"Kubernetes",
"Prometheus"
],
"tags": ["Kubernetes", "Prometheus"],
"templating": {
"list": [
{

View File

@@ -137,9 +137,7 @@
"justifyMode": "auto",
"orientation": "auto",
"reduceOptions": {
"calcs": [
"mean"
],
"calcs": ["mean"],
"fields": "",
"values": false
},
@@ -205,9 +203,7 @@
"justifyMode": "auto",
"orientation": "auto",
"reduceOptions": {
"calcs": [
"mean"
],
"calcs": ["mean"],
"fields": "",
"values": false
},
@@ -267,9 +263,7 @@
"justifyMode": "auto",
"orientation": "auto",
"reduceOptions": {
"calcs": [
"mean"
],
"calcs": ["mean"],
"fields": "",
"values": false
},
@@ -329,9 +323,7 @@
"justifyMode": "auto",
"orientation": "auto",
"reduceOptions": {
"calcs": [
"mean"
],
"calcs": ["mean"],
"fields": "",
"values": false
},
@@ -660,9 +652,7 @@
"minVizWidth": 75,
"orientation": "auto",
"reduceOptions": {
"calcs": [
"last"
],
"calcs": ["last"],
"fields": "",
"values": false
},
@@ -732,9 +722,7 @@
"minVizWidth": 75,
"orientation": "auto",
"reduceOptions": {
"calcs": [
"last"
],
"calcs": ["last"],
"fields": "",
"values": false
},
@@ -808,9 +796,7 @@
"minVizWidth": 75,
"orientation": "auto",
"reduceOptions": {
"calcs": [
"last"
],
"calcs": ["last"],
"fields": "",
"values": false
},
@@ -880,9 +866,7 @@
"minVizWidth": 75,
"orientation": "auto",
"reduceOptions": {
"calcs": [
"last"
],
"calcs": ["last"],
"fields": "",
"values": false
},
@@ -1000,9 +984,7 @@
"footer": {
"countRows": false,
"fields": "",
"reducer": [
"sum"
],
"reducer": ["sum"],
"show": false
},
"showHeader": true,
@@ -1532,11 +1514,7 @@
"id": 29,
"options": {
"legend": {
"calcs": [
"min",
"max",
"mean"
],
"calcs": ["min", "max", "mean"],
"displayMode": "table",
"placement": "right",
"showLegend": true
@@ -1638,11 +1616,7 @@
"id": 51,
"options": {
"legend": {
"calcs": [
"min",
"max",
"mean"
],
"calcs": ["min", "max", "mean"],
"displayMode": "table",
"placement": "right",
"showLegend": true
@@ -1744,11 +1718,7 @@
"id": 59,
"options": {
"legend": {
"calcs": [
"min",
"max",
"mean"
],
"calcs": ["min", "max", "mean"],
"displayMode": "table",
"placement": "right",
"showLegend": true,
@@ -2475,10 +2445,7 @@
],
"refresh": "30s",
"schemaVersion": 38,
"tags": [
"Kubernetes",
"Prometheus"
],
"tags": ["Kubernetes", "Prometheus"],
"templating": {
"list": [
{

View File

@@ -12,10 +12,10 @@ datasources:
manageAlerts: true
prometheusType: Prometheus
prometheusVersion: 2.49.0
cacheLevel: 'High'
cacheLevel: "High"
disableRecordingRules: false
# As of Grafana 10, the Prometheus data source can be configured to query live dashboards
# As of Grafana 10, the Prometheus data source can be configured to query live dashboards
# incrementally, instead of re-querying the entire duration on each dashboard refresh.
# Increasing the duration of the incrementalQueryOverlapWindow will increase the size of every incremental query,
# Increasing the duration of the incrementalQueryOverlapWindow will increase the size of every incremental query,
# but might be helpful for instances that have inconsistent results for recent data.
incrementalQueryOverlapWindow: 10m

View File

@@ -2,6 +2,5 @@
## Alert Rules
- [awesome-prometheus-alerts](https://github.com/samber/awesome-prometheus-alerts): Collection of Prometheus alerting rules
- [awesome-prometheus-alerts](https://github.com/samber/awesome-prometheus-alerts): Collection of
Prometheus alerting rules

View File

@@ -1,14 +1,13 @@
groups:
- name: EmbeddedExporter
- name: EmbeddedExporter
rules:
- alert: CorednsPanicCount
expr: 'increase(coredns_panics_total[1m]) > 0'
for: 0m
labels:
severity: critical
annotations:
summary: CoreDNS Panic Count (instance {{ $labels.instance }})
description: "Number of CoreDNS panics encountered\n VALUE = {{ $value }}\n LABELS = {{ $labels }}"
rules:
- alert: CorednsPanicCount
expr: "increase(coredns_panics_total[1m]) > 0"
for: 0m
labels:
severity: critical
annotations:
summary: CoreDNS Panic Count (instance {{ $labels.instance }})
description:
"Number of CoreDNS panics encountered\n VALUE = {{ $value }}\n LABELS = {{ $labels }}"

View File

@@ -1,122 +1,162 @@
groups:
- name: EmbeddedExporter
- name: EmbeddedExporter
rules:
- alert: EtcdInsufficientMembers
expr: "count(etcd_server_id) % 2 == 0"
for: 0m
labels:
severity: critical
annotations:
summary: Etcd insufficient Members (instance {{ $labels.instance }})
description:
"Etcd cluster should have an odd number of members\n VALUE = {{ $value }}\n LABELS =
{{ $labels }}"
rules:
- alert: EtcdNoLeader
expr: "etcd_server_has_leader == 0"
for: 0m
labels:
severity: critical
annotations:
summary: Etcd no Leader (instance {{ $labels.instance }})
description:
"Etcd cluster have no leader\n VALUE = {{ $value }}\n LABELS = {{ $labels }}"
- alert: EtcdInsufficientMembers
expr: 'count(etcd_server_id) % 2 == 0'
for: 0m
labels:
severity: critical
annotations:
summary: Etcd insufficient Members (instance {{ $labels.instance }})
description: "Etcd cluster should have an odd number of members\n VALUE = {{ $value }}\n LABELS = {{ $labels }}"
- alert: EtcdHighNumberOfLeaderChanges
expr: "increase(etcd_server_leader_changes_seen_total[10m]) > 2"
for: 0m
labels:
severity: warning
annotations:
summary: Etcd high number of leader changes (instance {{ $labels.instance }})
description:
"Etcd leader changed more than 2 times during 10 minutes\n VALUE = {{ $value
}}\n LABELS = {{ $labels }}"
- alert: EtcdNoLeader
expr: 'etcd_server_has_leader == 0'
for: 0m
labels:
severity: critical
annotations:
summary: Etcd no Leader (instance {{ $labels.instance }})
description: "Etcd cluster have no leader\n VALUE = {{ $value }}\n LABELS = {{ $labels }}"
- alert: EtcdHighNumberOfFailedGrpcRequests
expr:
'sum(rate(grpc_server_handled_total{grpc_code!="OK"}[1m])) BY (grpc_service, grpc_method)
/ sum(rate(grpc_server_handled_total[1m])) BY (grpc_service, grpc_method) > 0.01'
for: 2m
labels:
severity: warning
annotations:
summary: Etcd high number of failed GRPC requests (instance {{ $labels.instance }})
description:
"More than 1% GRPC request failure detected in Etcd\n VALUE = {{ $value }}\n LABELS =
{{ $labels }}"
- alert: EtcdHighNumberOfLeaderChanges
expr: 'increase(etcd_server_leader_changes_seen_total[10m]) > 2'
for: 0m
labels:
severity: warning
annotations:
summary: Etcd high number of leader changes (instance {{ $labels.instance }})
description: "Etcd leader changed more than 2 times during 10 minutes\n VALUE = {{ $value }}\n LABELS = {{ $labels }}"
- alert: EtcdHighNumberOfFailedGrpcRequests
expr:
'sum(rate(grpc_server_handled_total{grpc_code!="OK"}[1m])) BY (grpc_service, grpc_method)
/ sum(rate(grpc_server_handled_total[1m])) BY (grpc_service, grpc_method) > 0.05'
for: 2m
labels:
severity: critical
annotations:
summary: Etcd high number of failed GRPC requests (instance {{ $labels.instance }})
description:
"More than 5% GRPC request failure detected in Etcd\n VALUE = {{ $value }}\n LABELS =
{{ $labels }}"
- alert: EtcdHighNumberOfFailedGrpcRequests
expr: 'sum(rate(grpc_server_handled_total{grpc_code!="OK"}[1m])) BY (grpc_service, grpc_method) / sum(rate(grpc_server_handled_total[1m])) BY (grpc_service, grpc_method) > 0.01'
for: 2m
labels:
severity: warning
annotations:
summary: Etcd high number of failed GRPC requests (instance {{ $labels.instance }})
description: "More than 1% GRPC request failure detected in Etcd\n VALUE = {{ $value }}\n LABELS = {{ $labels }}"
- alert: EtcdGrpcRequestsSlow
expr:
'histogram_quantile(0.99,
sum(rate(grpc_server_handling_seconds_bucket{grpc_type="unary"}[1m])) by (grpc_service,
grpc_method, le)) > 0.15'
for: 2m
labels:
severity: warning
annotations:
summary: Etcd GRPC requests slow (instance {{ $labels.instance }})
description:
"GRPC requests slowing down, 99th percentile is over 0.15s\n VALUE = {{ $value
}}\n LABELS = {{ $labels }}"
- alert: EtcdHighNumberOfFailedGrpcRequests
expr: 'sum(rate(grpc_server_handled_total{grpc_code!="OK"}[1m])) BY (grpc_service, grpc_method) / sum(rate(grpc_server_handled_total[1m])) BY (grpc_service, grpc_method) > 0.05'
for: 2m
labels:
severity: critical
annotations:
summary: Etcd high number of failed GRPC requests (instance {{ $labels.instance }})
description: "More than 5% GRPC request failure detected in Etcd\n VALUE = {{ $value }}\n LABELS = {{ $labels }}"
- alert: EtcdHighNumberOfFailedHttpRequests
expr:
"sum(rate(etcd_http_failed_total[1m])) BY (method) /
sum(rate(etcd_http_received_total[1m])) BY (method) > 0.01"
for: 2m
labels:
severity: warning
annotations:
summary: Etcd high number of failed HTTP requests (instance {{ $labels.instance }})
description:
"More than 1% HTTP failure detected in Etcd\n VALUE = {{ $value }}\n LABELS = {{
$labels }}"
- alert: EtcdGrpcRequestsSlow
expr: 'histogram_quantile(0.99, sum(rate(grpc_server_handling_seconds_bucket{grpc_type="unary"}[1m])) by (grpc_service, grpc_method, le)) > 0.15'
for: 2m
labels:
severity: warning
annotations:
summary: Etcd GRPC requests slow (instance {{ $labels.instance }})
description: "GRPC requests slowing down, 99th percentile is over 0.15s\n VALUE = {{ $value }}\n LABELS = {{ $labels }}"
- alert: EtcdHighNumberOfFailedHttpRequests
expr:
"sum(rate(etcd_http_failed_total[1m])) BY (method) /
sum(rate(etcd_http_received_total[1m])) BY (method) > 0.05"
for: 2m
labels:
severity: critical
annotations:
summary: Etcd high number of failed HTTP requests (instance {{ $labels.instance }})
description:
"More than 5% HTTP failure detected in Etcd\n VALUE = {{ $value }}\n LABELS = {{
$labels }}"
- alert: EtcdHighNumberOfFailedHttpRequests
expr: 'sum(rate(etcd_http_failed_total[1m])) BY (method) / sum(rate(etcd_http_received_total[1m])) BY (method) > 0.01'
for: 2m
labels:
severity: warning
annotations:
summary: Etcd high number of failed HTTP requests (instance {{ $labels.instance }})
description: "More than 1% HTTP failure detected in Etcd\n VALUE = {{ $value }}\n LABELS = {{ $labels }}"
- alert: EtcdHttpRequestsSlow
expr:
"histogram_quantile(0.99, rate(etcd_http_successful_duration_seconds_bucket[1m])) > 0.15"
for: 2m
labels:
severity: warning
annotations:
summary: Etcd HTTP requests slow (instance {{ $labels.instance }})
description:
"HTTP requests slowing down, 99th percentile is over 0.15s\n VALUE = {{ $value
}}\n LABELS = {{ $labels }}"
- alert: EtcdHighNumberOfFailedHttpRequests
expr: 'sum(rate(etcd_http_failed_total[1m])) BY (method) / sum(rate(etcd_http_received_total[1m])) BY (method) > 0.05'
for: 2m
labels:
severity: critical
annotations:
summary: Etcd high number of failed HTTP requests (instance {{ $labels.instance }})
description: "More than 5% HTTP failure detected in Etcd\n VALUE = {{ $value }}\n LABELS = {{ $labels }}"
- alert: EtcdMemberCommunicationSlow
expr:
"histogram_quantile(0.99, rate(etcd_network_peer_round_trip_time_seconds_bucket[1m])) >
0.15"
for: 2m
labels:
severity: warning
annotations:
summary: Etcd member communication slow (instance {{ $labels.instance }})
description:
"Etcd member communication slowing down, 99th percentile is over 0.15s\n VALUE = {{
$value }}\n LABELS = {{ $labels }}"
- alert: EtcdHttpRequestsSlow
expr: 'histogram_quantile(0.99, rate(etcd_http_successful_duration_seconds_bucket[1m])) > 0.15'
for: 2m
labels:
severity: warning
annotations:
summary: Etcd HTTP requests slow (instance {{ $labels.instance }})
description: "HTTP requests slowing down, 99th percentile is over 0.15s\n VALUE = {{ $value }}\n LABELS = {{ $labels }}"
- alert: EtcdHighNumberOfFailedProposals
expr: "increase(etcd_server_proposals_failed_total[1h]) > 5"
for: 2m
labels:
severity: warning
annotations:
summary: Etcd high number of failed proposals (instance {{ $labels.instance }})
description:
"Etcd server got more than 5 failed proposals past hour\n VALUE = {{ $value
}}\n LABELS = {{ $labels }}"
- alert: EtcdMemberCommunicationSlow
expr: 'histogram_quantile(0.99, rate(etcd_network_peer_round_trip_time_seconds_bucket[1m])) > 0.15'
for: 2m
labels:
severity: warning
annotations:
summary: Etcd member communication slow (instance {{ $labels.instance }})
description: "Etcd member communication slowing down, 99th percentile is over 0.15s\n VALUE = {{ $value }}\n LABELS = {{ $labels }}"
- alert: EtcdHighFsyncDurations
expr:
"histogram_quantile(0.99, rate(etcd_disk_wal_fsync_duration_seconds_bucket[1m])) > 0.5"
for: 2m
labels:
severity: warning
annotations:
summary: Etcd high fsync durations (instance {{ $labels.instance }})
description:
"Etcd WAL fsync duration increasing, 99th percentile is over 0.5s\n VALUE = {{ $value
}}\n LABELS = {{ $labels }}"
- alert: EtcdHighNumberOfFailedProposals
expr: 'increase(etcd_server_proposals_failed_total[1h]) > 5'
for: 2m
labels:
severity: warning
annotations:
summary: Etcd high number of failed proposals (instance {{ $labels.instance }})
description: "Etcd server got more than 5 failed proposals past hour\n VALUE = {{ $value }}\n LABELS = {{ $labels }}"
- alert: EtcdHighFsyncDurations
expr: 'histogram_quantile(0.99, rate(etcd_disk_wal_fsync_duration_seconds_bucket[1m])) > 0.5'
for: 2m
labels:
severity: warning
annotations:
summary: Etcd high fsync durations (instance {{ $labels.instance }})
description: "Etcd WAL fsync duration increasing, 99th percentile is over 0.5s\n VALUE = {{ $value }}\n LABELS = {{ $labels }}"
- alert: EtcdHighCommitDurations
expr: 'histogram_quantile(0.99, rate(etcd_disk_backend_commit_duration_seconds_bucket[1m])) > 0.25'
for: 2m
labels:
severity: warning
annotations:
summary: Etcd high commit durations (instance {{ $labels.instance }})
description: "Etcd commit duration increasing, 99th percentile is over 0.25s\n VALUE = {{ $value }}\n LABELS = {{ $labels }}"
- alert: EtcdHighCommitDurations
expr:
"histogram_quantile(0.99, rate(etcd_disk_backend_commit_duration_seconds_bucket[1m])) >
0.25"
for: 2m
labels:
severity: warning
annotations:
summary: Etcd high commit durations (instance {{ $labels.instance }})
description:
"Etcd commit duration increasing, 99th percentile is over 0.25s\n VALUE = {{ $value
}}\n LABELS = {{ $labels }}"

View File

@@ -1,95 +1,123 @@
groups:
- name: EmbeddedExporter
- name: EmbeddedExporter
rules:
- alert: IstioKubernetesGatewayAvailabilityDrop
expr:
'min(kube_deployment_status_replicas_available{deployment="istio-ingressgateway",
namespace="istio-system"}) without (instance, pod) < 2'
for: 1m
labels:
severity: warning
annotations:
summary: Istio Kubernetes gateway availability drop (instance {{ $labels.instance }})
description:
"Gateway pods have dropped. Inbound traffic will likely be affected.\n VALUE = {{
$value }}\n LABELS = {{ $labels }}"
rules:
- alert: IstioPilotHighTotalRequestRate
expr: "sum(rate(pilot_xds_push_errors[1m])) / sum(rate(pilot_xds_pushes[1m])) * 100 > 5"
for: 1m
labels:
severity: warning
annotations:
summary: Istio Pilot high total request rate (instance {{ $labels.instance }})
description:
"Number of Istio Pilot push errors is too high (> 5%). Envoy sidecars might have
outdated configuration.\n VALUE = {{ $value }}\n LABELS = {{ $labels }}"
- alert: IstioKubernetesGatewayAvailabilityDrop
expr: 'min(kube_deployment_status_replicas_available{deployment="istio-ingressgateway", namespace="istio-system"}) without (instance, pod) < 2'
for: 1m
labels:
severity: warning
annotations:
summary: Istio Kubernetes gateway availability drop (instance {{ $labels.instance }})
description: "Gateway pods have dropped. Inbound traffic will likely be affected.\n VALUE = {{ $value }}\n LABELS = {{ $labels }}"
- alert: IstioMixerPrometheusDispatchesLow
expr: 'sum(rate(mixer_runtime_dispatches_total{adapter=~"prometheus"}[1m])) < 180'
for: 1m
labels:
severity: warning
annotations:
summary: Istio Mixer Prometheus dispatches low (instance {{ $labels.instance }})
description:
"Number of Mixer dispatches to Prometheus is too low. Istio metrics might not be being
exported properly.\n VALUE = {{ $value }}\n LABELS = {{ $labels }}"
- alert: IstioPilotHighTotalRequestRate
expr: 'sum(rate(pilot_xds_push_errors[1m])) / sum(rate(pilot_xds_pushes[1m])) * 100 > 5'
for: 1m
labels:
severity: warning
annotations:
summary: Istio Pilot high total request rate (instance {{ $labels.instance }})
description: "Number of Istio Pilot push errors is too high (> 5%). Envoy sidecars might have outdated configuration.\n VALUE = {{ $value }}\n LABELS = {{ $labels }}"
- alert: IstioHighTotalRequestRate
expr: 'sum(rate(istio_requests_total{reporter="destination"}[5m])) > 1000'
for: 2m
labels:
severity: warning
annotations:
summary: Istio high total request rate (instance {{ $labels.instance }})
description:
"Global request rate in the service mesh is unusually high.\n VALUE = {{ $value
}}\n LABELS = {{ $labels }}"
- alert: IstioMixerPrometheusDispatchesLow
expr: 'sum(rate(mixer_runtime_dispatches_total{adapter=~"prometheus"}[1m])) < 180'
for: 1m
labels:
severity: warning
annotations:
summary: Istio Mixer Prometheus dispatches low (instance {{ $labels.instance }})
description: "Number of Mixer dispatches to Prometheus is too low. Istio metrics might not be being exported properly.\n VALUE = {{ $value }}\n LABELS = {{ $labels }}"
- alert: IstioLowTotalRequestRate
expr: 'sum(rate(istio_requests_total{reporter="destination"}[5m])) < 100'
for: 2m
labels:
severity: warning
annotations:
summary: Istio low total request rate (instance {{ $labels.instance }})
description:
"Global request rate in the service mesh is unusually low.\n VALUE = {{ $value
}}\n LABELS = {{ $labels }}"
- alert: IstioHighTotalRequestRate
expr: 'sum(rate(istio_requests_total{reporter="destination"}[5m])) > 1000'
for: 2m
labels:
severity: warning
annotations:
summary: Istio high total request rate (instance {{ $labels.instance }})
description: "Global request rate in the service mesh is unusually high.\n VALUE = {{ $value }}\n LABELS = {{ $labels }}"
- alert: IstioHigh4xxErrorRate
expr:
'sum(rate(istio_requests_total{reporter="destination", response_code=~"4.*"}[5m])) /
sum(rate(istio_requests_total{reporter="destination"}[5m])) * 100 > 5'
for: 1m
labels:
severity: warning
annotations:
summary: Istio high 4xx error rate (instance {{ $labels.instance }})
description:
"High percentage of HTTP 5xx responses in Istio (> 5%).\n VALUE = {{ $value
}}\n LABELS = {{ $labels }}"
- alert: IstioLowTotalRequestRate
expr: 'sum(rate(istio_requests_total{reporter="destination"}[5m])) < 100'
for: 2m
labels:
severity: warning
annotations:
summary: Istio low total request rate (instance {{ $labels.instance }})
description: "Global request rate in the service mesh is unusually low.\n VALUE = {{ $value }}\n LABELS = {{ $labels }}"
- alert: IstioHigh5xxErrorRate
expr:
'sum(rate(istio_requests_total{reporter="destination", response_code=~"5.*"}[5m])) /
sum(rate(istio_requests_total{reporter="destination"}[5m])) * 100 > 5'
for: 1m
labels:
severity: warning
annotations:
summary: Istio high 5xx error rate (instance {{ $labels.instance }})
description:
"High percentage of HTTP 5xx responses in Istio (> 5%).\n VALUE = {{ $value
}}\n LABELS = {{ $labels }}"
- alert: IstioHigh4xxErrorRate
expr: 'sum(rate(istio_requests_total{reporter="destination", response_code=~"4.*"}[5m])) / sum(rate(istio_requests_total{reporter="destination"}[5m])) * 100 > 5'
for: 1m
labels:
severity: warning
annotations:
summary: Istio high 4xx error rate (instance {{ $labels.instance }})
description: "High percentage of HTTP 5xx responses in Istio (> 5%).\n VALUE = {{ $value }}\n LABELS = {{ $labels }}"
- alert: IstioHighRequestLatency
expr:
'rate(istio_request_duration_milliseconds_sum{reporter="destination"}[1m]) /
rate(istio_request_duration_milliseconds_count{reporter="destination"}[1m]) > 100'
for: 1m
labels:
severity: warning
annotations:
summary: Istio high request latency (instance {{ $labels.instance }})
description:
"Istio average requests execution is longer than 100ms.\n VALUE = {{ $value
}}\n LABELS = {{ $labels }}"
- alert: IstioHigh5xxErrorRate
expr: 'sum(rate(istio_requests_total{reporter="destination", response_code=~"5.*"}[5m])) / sum(rate(istio_requests_total{reporter="destination"}[5m])) * 100 > 5'
for: 1m
labels:
severity: warning
annotations:
summary: Istio high 5xx error rate (instance {{ $labels.instance }})
description: "High percentage of HTTP 5xx responses in Istio (> 5%).\n VALUE = {{ $value }}\n LABELS = {{ $labels }}"
- alert: IstioLatency99Percentile
expr:
"histogram_quantile(0.99, sum(rate(istio_request_duration_milliseconds_bucket[1m])) by
(destination_canonical_service, destination_workload_namespace, source_canonical_service,
source_workload_namespace, le)) > 1000"
for: 1m
labels:
severity: warning
annotations:
summary: Istio latency 99 percentile (instance {{ $labels.instance }})
description:
"Istio 1% slowest requests are longer than 1000ms.\n VALUE = {{ $value }}\n LABELS =
{{ $labels }}"
- alert: IstioHighRequestLatency
expr: 'rate(istio_request_duration_milliseconds_sum{reporter="destination"}[1m]) / rate(istio_request_duration_milliseconds_count{reporter="destination"}[1m]) > 100'
for: 1m
labels:
severity: warning
annotations:
summary: Istio high request latency (instance {{ $labels.instance }})
description: "Istio average requests execution is longer than 100ms.\n VALUE = {{ $value }}\n LABELS = {{ $labels }}"
- alert: IstioLatency99Percentile
expr: 'histogram_quantile(0.99, sum(rate(istio_request_duration_milliseconds_bucket[1m])) by (destination_canonical_service, destination_workload_namespace, source_canonical_service, source_workload_namespace, le)) > 1000'
for: 1m
labels:
severity: warning
annotations:
summary: Istio latency 99 percentile (instance {{ $labels.instance }})
description: "Istio 1% slowest requests are longer than 1000ms.\n VALUE = {{ $value }}\n LABELS = {{ $labels }}"
- alert: IstioPilotDuplicateEntry
expr: 'sum(rate(pilot_duplicate_envoy_clusters{}[5m])) > 0'
for: 0m
labels:
severity: critical
annotations:
summary: Istio Pilot Duplicate Entry (instance {{ $labels.instance }})
description: "Istio pilot duplicate entry error.\n VALUE = {{ $value }}\n LABELS = {{ $labels }}"
- alert: IstioPilotDuplicateEntry
expr: "sum(rate(pilot_duplicate_envoy_clusters{}[5m])) > 0"
for: 0m
labels:
severity: critical
annotations:
summary: Istio Pilot Duplicate Entry (instance {{ $labels.instance }})
description:
"Istio pilot duplicate entry error.\n VALUE = {{ $value }}\n LABELS = {{ $labels }}"

View File

@@ -1,311 +1,435 @@
groups:
- name: KubestateExporter
- name: KubestateExporter
rules:
- alert: KubernetesNodeNotReady
expr: 'kube_node_status_condition{condition="Ready",status="true"} == 0'
for: 10m
labels:
severity: critical
annotations:
summary: Kubernetes Node ready (node {{ $labels.node }})
description:
"Node {{ $labels.node }} has been unready for a long time\n VALUE = {{ $value
}}\n LABELS = {{ $labels }}"
rules:
- alert: KubernetesNodeMemoryPressure
expr: 'kube_node_status_condition{condition="MemoryPressure",status="true"} == 1'
for: 2m
labels:
severity: critical
annotations:
summary: Kubernetes memory pressure (node {{ $labels.node }})
description:
"Node {{ $labels.node }} has MemoryPressure condition\n VALUE = {{ $value }}\n LABELS
= {{ $labels }}"
- alert: KubernetesNodeNotReady
expr: 'kube_node_status_condition{condition="Ready",status="true"} == 0'
for: 10m
labels:
severity: critical
annotations:
summary: Kubernetes Node ready (node {{ $labels.node }})
description: "Node {{ $labels.node }} has been unready for a long time\n VALUE = {{ $value }}\n LABELS = {{ $labels }}"
- alert: KubernetesNodeDiskPressure
expr: 'kube_node_status_condition{condition="DiskPressure",status="true"} == 1'
for: 2m
labels:
severity: critical
annotations:
summary: Kubernetes disk pressure (node {{ $labels.node }})
description:
"Node {{ $labels.node }} has DiskPressure condition\n VALUE = {{ $value }}\n LABELS =
{{ $labels }}"
- alert: KubernetesNodeMemoryPressure
expr: 'kube_node_status_condition{condition="MemoryPressure",status="true"} == 1'
for: 2m
labels:
severity: critical
annotations:
summary: Kubernetes memory pressure (node {{ $labels.node }})
description: "Node {{ $labels.node }} has MemoryPressure condition\n VALUE = {{ $value }}\n LABELS = {{ $labels }}"
- alert: KubernetesNodeNetworkUnavailable
expr: 'kube_node_status_condition{condition="NetworkUnavailable",status="true"} == 1'
for: 2m
labels:
severity: critical
annotations:
summary: Kubernetes Node network unavailable (instance {{ $labels.instance }})
description:
"Node {{ $labels.node }} has NetworkUnavailable condition\n VALUE = {{ $value
}}\n LABELS = {{ $labels }}"
- alert: KubernetesNodeDiskPressure
expr: 'kube_node_status_condition{condition="DiskPressure",status="true"} == 1'
for: 2m
labels:
severity: critical
annotations:
summary: Kubernetes disk pressure (node {{ $labels.node }})
description: "Node {{ $labels.node }} has DiskPressure condition\n VALUE = {{ $value }}\n LABELS = {{ $labels }}"
- alert: KubernetesNodeOutOfPodCapacity
expr:
'sum by (node) ((kube_pod_status_phase{phase="Running"} == 1) + on(uid) group_left(node)
(0 * kube_pod_info{pod_template_hash=""})) / sum by (node)
(kube_node_status_allocatable{resource="pods"}) * 100 > 90'
for: 2m
labels:
severity: warning
annotations:
summary: Kubernetes Node out of pod capacity (instance {{ $labels.instance }})
description:
"Node {{ $labels.node }} is out of pod capacity\n VALUE = {{ $value }}\n LABELS = {{
$labels }}"
- alert: KubernetesNodeNetworkUnavailable
expr: 'kube_node_status_condition{condition="NetworkUnavailable",status="true"} == 1'
for: 2m
labels:
severity: critical
annotations:
summary: Kubernetes Node network unavailable (instance {{ $labels.instance }})
description: "Node {{ $labels.node }} has NetworkUnavailable condition\n VALUE = {{ $value }}\n LABELS = {{ $labels }}"
- alert: KubernetesContainerOomKiller
expr:
'(kube_pod_container_status_restarts_total - kube_pod_container_status_restarts_total
offset 10m >= 1) and ignoring (reason)
min_over_time(kube_pod_container_status_last_terminated_reason{reason="OOMKilled"}[10m])
== 1'
for: 0m
labels:
severity: warning
annotations:
summary:
Kubernetes container oom killer ({{ $labels.namespace }}/{{ $labels.pod }}:{{
$labels.container }})
description:
"Container {{ $labels.container }} in pod {{ $labels.namespace }}/{{ $labels.pod }} has
been OOMKilled {{ $value }} times in the last 10 minutes.\n VALUE = {{ $value
}}\n LABELS = {{ $labels }}"
- alert: KubernetesNodeOutOfPodCapacity
expr: 'sum by (node) ((kube_pod_status_phase{phase="Running"} == 1) + on(uid) group_left(node) (0 * kube_pod_info{pod_template_hash=""})) / sum by (node) (kube_node_status_allocatable{resource="pods"}) * 100 > 90'
for: 2m
labels:
severity: warning
annotations:
summary: Kubernetes Node out of pod capacity (instance {{ $labels.instance }})
description: "Node {{ $labels.node }} is out of pod capacity\n VALUE = {{ $value }}\n LABELS = {{ $labels }}"
- alert: KubernetesJobFailed
expr: "kube_job_status_failed > 0"
for: 0m
labels:
severity: warning
annotations:
summary: Kubernetes Job failed ({{ $labels.namespace }}/{{ $labels.job_name }})
description:
"Job {{ $labels.namespace }}/{{ $labels.job_name }} failed to complete\n VALUE = {{
$value }}\n LABELS = {{ $labels }}"
- alert: KubernetesContainerOomKiller
expr: '(kube_pod_container_status_restarts_total - kube_pod_container_status_restarts_total offset 10m >= 1) and ignoring (reason) min_over_time(kube_pod_container_status_last_terminated_reason{reason="OOMKilled"}[10m]) == 1'
for: 0m
labels:
severity: warning
annotations:
summary: Kubernetes container oom killer ({{ $labels.namespace }}/{{ $labels.pod }}:{{ $labels.container }})
description: "Container {{ $labels.container }} in pod {{ $labels.namespace }}/{{ $labels.pod }} has been OOMKilled {{ $value }} times in the last 10 minutes.\n VALUE = {{ $value }}\n LABELS = {{ $labels }}"
- alert: KubernetesCronjobSuspended
expr: "kube_cronjob_spec_suspend != 0"
for: 0m
labels:
severity: warning
annotations:
summary: Kubernetes CronJob suspended ({{ $labels.namespace }}/{{ $labels.cronjob }})
description:
"CronJob {{ $labels.namespace }}/{{ $labels.cronjob }} is suspended\n VALUE = {{ $value
}}\n LABELS = {{ $labels }}"
- alert: KubernetesJobFailed
expr: 'kube_job_status_failed > 0'
for: 0m
labels:
severity: warning
annotations:
summary: Kubernetes Job failed ({{ $labels.namespace }}/{{ $labels.job_name }})
description: "Job {{ $labels.namespace }}/{{ $labels.job_name }} failed to complete\n VALUE = {{ $value }}\n LABELS = {{ $labels }}"
- alert: KubernetesPersistentvolumeclaimPending
expr: 'kube_persistentvolumeclaim_status_phase{phase="Pending"} == 1'
for: 2m
labels:
severity: warning
annotations:
summary:
Kubernetes PersistentVolumeClaim pending ({{ $labels.namespace }}/{{
$labels.persistentvolumeclaim }})
description:
"PersistentVolumeClaim {{ $labels.namespace }}/{{ $labels.persistentvolumeclaim }} is
pending\n VALUE = {{ $value }}\n LABELS = {{ $labels }}"
- alert: KubernetesCronjobSuspended
expr: 'kube_cronjob_spec_suspend != 0'
for: 0m
labels:
severity: warning
annotations:
summary: Kubernetes CronJob suspended ({{ $labels.namespace }}/{{ $labels.cronjob }})
description: "CronJob {{ $labels.namespace }}/{{ $labels.cronjob }} is suspended\n VALUE = {{ $value }}\n LABELS = {{ $labels }}"
- alert: KubernetesVolumeOutOfDiskSpace
expr:
"kubelet_volume_stats_available_bytes / kubelet_volume_stats_capacity_bytes * 100 < 10"
for: 2m
labels:
severity: warning
annotations:
summary: Kubernetes Volume out of disk space (instance {{ $labels.instance }})
description:
"Volume is almost full (< 10% left)\n VALUE = {{ $value }}\n LABELS = {{ $labels }}"
- alert: KubernetesPersistentvolumeclaimPending
expr: 'kube_persistentvolumeclaim_status_phase{phase="Pending"} == 1'
for: 2m
labels:
severity: warning
annotations:
summary: Kubernetes PersistentVolumeClaim pending ({{ $labels.namespace }}/{{ $labels.persistentvolumeclaim }})
description: "PersistentVolumeClaim {{ $labels.namespace }}/{{ $labels.persistentvolumeclaim }} is pending\n VALUE = {{ $value }}\n LABELS = {{ $labels }}"
- alert: KubernetesVolumeFullInFourDays
expr: "predict_linear(kubelet_volume_stats_available_bytes[6h:5m], 4 * 24 * 3600) < 0"
for: 0m
labels:
severity: critical
annotations:
summary: Kubernetes Volume full in four days (instance {{ $labels.instance }})
description:
"Volume under {{ $labels.namespace }}/{{ $labels.persistentvolumeclaim }} is expected to
fill up within four days. Currently {{ $value | humanize }}% is available.\n VALUE = {{
$value }}\n LABELS = {{ $labels }}"
- alert: KubernetesVolumeOutOfDiskSpace
expr: 'kubelet_volume_stats_available_bytes / kubelet_volume_stats_capacity_bytes * 100 < 10'
for: 2m
labels:
severity: warning
annotations:
summary: Kubernetes Volume out of disk space (instance {{ $labels.instance }})
description: "Volume is almost full (< 10% left)\n VALUE = {{ $value }}\n LABELS = {{ $labels }}"
- alert: KubernetesPersistentvolumeError
expr:
'kube_persistentvolume_status_phase{phase=~"Failed|Pending", job="kube-state-metrics"} > 0'
for: 0m
labels:
severity: critical
annotations:
summary:
Kubernetes PersistentVolumeClaim pending ({{ $labels.namespace }}/{{
$labels.persistentvolumeclaim }})
description:
"Persistent volume {{ $labels.persistentvolume }} is in bad state\n VALUE = {{ $value
}}\n LABELS = {{ $labels }}"
- alert: KubernetesVolumeFullInFourDays
expr: 'predict_linear(kubelet_volume_stats_available_bytes[6h:5m], 4 * 24 * 3600) < 0'
for: 0m
labels:
severity: critical
annotations:
summary: Kubernetes Volume full in four days (instance {{ $labels.instance }})
description: "Volume under {{ $labels.namespace }}/{{ $labels.persistentvolumeclaim }} is expected to fill up within four days. Currently {{ $value | humanize }}% is available.\n VALUE = {{ $value }}\n LABELS = {{ $labels }}"
- alert: KubernetesStatefulsetDown
expr: "kube_statefulset_replicas != kube_statefulset_status_replicas_ready > 0"
for: 1m
labels:
severity: critical
annotations:
summary: Kubernetes StatefulSet down ({{ $labels.namespace }}/{{ $labels.statefulset }})
description:
"StatefulSet {{ $labels.namespace }}/{{ $labels.statefulset }} went down\n VALUE = {{
$value }}\n LABELS = {{ $labels }}"
- alert: KubernetesPersistentvolumeError
expr: 'kube_persistentvolume_status_phase{phase=~"Failed|Pending", job="kube-state-metrics"} > 0'
for: 0m
labels:
severity: critical
annotations:
summary: Kubernetes PersistentVolumeClaim pending ({{ $labels.namespace }}/{{ $labels.persistentvolumeclaim }})
description: "Persistent volume {{ $labels.persistentvolume }} is in bad state\n VALUE = {{ $value }}\n LABELS = {{ $labels }}"
- alert: KubernetesHpaScaleInability
expr:
'kube_horizontalpodautoscaler_status_condition{status="false", condition="AbleToScale"} ==
1'
for: 2m
labels:
severity: warning
annotations:
summary: Kubernetes HPA scale inability (instance {{ $labels.instance }})
description:
"HPA {{ $labels.namespace }}/{{ $labels.horizontalpodautoscaler }} is unable to
scale\n VALUE = {{ $value }}\n LABELS = {{ $labels }}"
- alert: KubernetesStatefulsetDown
expr: 'kube_statefulset_replicas != kube_statefulset_status_replicas_ready > 0'
for: 1m
labels:
severity: critical
annotations:
summary: Kubernetes StatefulSet down ({{ $labels.namespace }}/{{ $labels.statefulset }})
description: "StatefulSet {{ $labels.namespace }}/{{ $labels.statefulset }} went down\n VALUE = {{ $value }}\n LABELS = {{ $labels }}"
- alert: KubernetesHpaMetricsUnavailability
expr:
'kube_horizontalpodautoscaler_status_condition{status="false", condition="ScalingActive"}
== 1'
for: 0m
labels:
severity: warning
annotations:
summary: Kubernetes HPA metrics unavailability (instance {{ $labels.instance }})
description:
"HPA {{ $labels.namespace }}/{{ $labels.horizontalpodautoscaler }} is unable to collect
metrics\n VALUE = {{ $value }}\n LABELS = {{ $labels }}"
- alert: KubernetesHpaScaleInability
expr: 'kube_horizontalpodautoscaler_status_condition{status="false", condition="AbleToScale"} == 1'
for: 2m
labels:
severity: warning
annotations:
summary: Kubernetes HPA scale inability (instance {{ $labels.instance }})
description: "HPA {{ $labels.namespace }}/{{ $labels.horizontalpodautoscaler }} is unable to scale\n VALUE = {{ $value }}\n LABELS = {{ $labels }}"
- alert: KubernetesHpaScaleMaximum
expr:
"kube_horizontalpodautoscaler_status_desired_replicas >=
kube_horizontalpodautoscaler_spec_max_replicas"
for: 2m
labels:
severity: info
annotations:
summary: Kubernetes HPA scale maximum (instance {{ $labels.instance }})
description:
"HPA {{ $labels.namespace }}/{{ $labels.horizontalpodautoscaler }} has hit maximum
number of desired pods\n VALUE = {{ $value }}\n LABELS = {{ $labels }}"
- alert: KubernetesHpaMetricsUnavailability
expr: 'kube_horizontalpodautoscaler_status_condition{status="false", condition="ScalingActive"} == 1'
for: 0m
labels:
severity: warning
annotations:
summary: Kubernetes HPA metrics unavailability (instance {{ $labels.instance }})
description: "HPA {{ $labels.namespace }}/{{ $labels.horizontalpodautoscaler }} is unable to collect metrics\n VALUE = {{ $value }}\n LABELS = {{ $labels }}"
- alert: KubernetesHpaUnderutilized
expr:
"max(quantile_over_time(0.5, kube_horizontalpodautoscaler_status_desired_replicas[1d]) ==
kube_horizontalpodautoscaler_spec_min_replicas) by (horizontalpodautoscaler) > 3"
for: 0m
labels:
severity: info
annotations:
summary: Kubernetes HPA underutilized (instance {{ $labels.instance }})
description:
"HPA {{ $labels.namespace }}/{{ $labels.horizontalpodautoscaler }} is constantly at
minimum replicas for 50% of the time. Potential cost saving here.\n VALUE = {{ $value
}}\n LABELS = {{ $labels }}"
- alert: KubernetesHpaScaleMaximum
expr: 'kube_horizontalpodautoscaler_status_desired_replicas >= kube_horizontalpodautoscaler_spec_max_replicas'
for: 2m
labels:
severity: info
annotations:
summary: Kubernetes HPA scale maximum (instance {{ $labels.instance }})
description: "HPA {{ $labels.namespace }}/{{ $labels.horizontalpodautoscaler }} has hit maximum number of desired pods\n VALUE = {{ $value }}\n LABELS = {{ $labels }}"
- alert: KubernetesPodNotHealthy
expr: 'sum by (namespace, pod) (kube_pod_status_phase{phase=~"Pending|Unknown|Failed"}) > 0'
for: 15m
labels:
severity: critical
annotations:
summary: Kubernetes Pod not healthy ({{ $labels.namespace }}/{{ $labels.pod }})
description:
"Pod {{ $labels.namespace }}/{{ $labels.pod }} has been in a non-running state for
longer than 15 minutes.\n VALUE = {{ $value }}\n LABELS = {{ $labels }}"
- alert: KubernetesHpaUnderutilized
expr: 'max(quantile_over_time(0.5, kube_horizontalpodautoscaler_status_desired_replicas[1d]) == kube_horizontalpodautoscaler_spec_min_replicas) by (horizontalpodautoscaler) > 3'
for: 0m
labels:
severity: info
annotations:
summary: Kubernetes HPA underutilized (instance {{ $labels.instance }})
description: "HPA {{ $labels.namespace }}/{{ $labels.horizontalpodautoscaler }} is constantly at minimum replicas for 50% of the time. Potential cost saving here.\n VALUE = {{ $value }}\n LABELS = {{ $labels }}"
- alert: KubernetesPodCrashLooping
expr: "increase(kube_pod_container_status_restarts_total[1m]) > 3"
for: 2m
labels:
severity: warning
annotations:
summary: Kubernetes pod crash looping ({{ $labels.namespace }}/{{ $labels.pod }})
description:
"Pod {{ $labels.namespace }}/{{ $labels.pod }} is crash looping\n VALUE = {{ $value
}}\n LABELS = {{ $labels }}"
- alert: KubernetesPodNotHealthy
expr: 'sum by (namespace, pod) (kube_pod_status_phase{phase=~"Pending|Unknown|Failed"}) > 0'
for: 15m
labels:
severity: critical
annotations:
summary: Kubernetes Pod not healthy ({{ $labels.namespace }}/{{ $labels.pod }})
description: "Pod {{ $labels.namespace }}/{{ $labels.pod }} has been in a non-running state for longer than 15 minutes.\n VALUE = {{ $value }}\n LABELS = {{ $labels }}"
- alert: KubernetesReplicasetReplicasMismatch
expr: "kube_replicaset_spec_replicas != kube_replicaset_status_ready_replicas"
for: 10m
labels:
severity: warning
annotations:
summary:
Kubernetes ReplicasSet mismatch ({{ $labels.namespace }}/{{ $labels.replicaset }})
description:
"ReplicaSet {{ $labels.namespace }}/{{ $labels.replicaset }} replicas mismatch\n VALUE
= {{ $value }}\n LABELS = {{ $labels }}"
- alert: KubernetesPodCrashLooping
expr: 'increase(kube_pod_container_status_restarts_total[1m]) > 3'
for: 2m
labels:
severity: warning
annotations:
summary: Kubernetes pod crash looping ({{ $labels.namespace }}/{{ $labels.pod }})
description: "Pod {{ $labels.namespace }}/{{ $labels.pod }} is crash looping\n VALUE = {{ $value }}\n LABELS = {{ $labels }}"
- alert: KubernetesDeploymentReplicasMismatch
expr: "kube_deployment_spec_replicas != kube_deployment_status_replicas_available"
for: 10m
labels:
severity: warning
annotations:
summary:
Kubernetes Deployment replicas mismatch ({{ $labels.namespace }}/{{ $labels.deployment
}})
description:
"Deployment {{ $labels.namespace }}/{{ $labels.deployment }} replicas mismatch\n VALUE
= {{ $value }}\n LABELS = {{ $labels }}"
- alert: KubernetesReplicasetReplicasMismatch
expr: 'kube_replicaset_spec_replicas != kube_replicaset_status_ready_replicas'
for: 10m
labels:
severity: warning
annotations:
summary: Kubernetes ReplicasSet mismatch ({{ $labels.namespace }}/{{ $labels.replicaset }})
description: "ReplicaSet {{ $labels.namespace }}/{{ $labels.replicaset }} replicas mismatch\n VALUE = {{ $value }}\n LABELS = {{ $labels }}"
- alert: KubernetesStatefulsetReplicasMismatch
expr: "kube_statefulset_status_replicas_ready != kube_statefulset_status_replicas"
for: 10m
labels:
severity: warning
annotations:
summary: Kubernetes StatefulSet replicas mismatch (instance {{ $labels.instance }})
description:
"StatefulSet does not match the expected number of replicas.\n VALUE = {{ $value
}}\n LABELS = {{ $labels }}"
- alert: KubernetesDeploymentReplicasMismatch
expr: 'kube_deployment_spec_replicas != kube_deployment_status_replicas_available'
for: 10m
labels:
severity: warning
annotations:
summary: Kubernetes Deployment replicas mismatch ({{ $labels.namespace }}/{{ $labels.deployment }})
description: "Deployment {{ $labels.namespace }}/{{ $labels.deployment }} replicas mismatch\n VALUE = {{ $value }}\n LABELS = {{ $labels }}"
- alert: KubernetesDeploymentGenerationMismatch
expr: "kube_deployment_status_observed_generation != kube_deployment_metadata_generation"
for: 10m
labels:
severity: critical
annotations:
summary:
Kubernetes Deployment generation mismatch ({{ $labels.namespace }}/{{ $labels.deployment
}})
description:
"Deployment {{ $labels.namespace }}/{{ $labels.deployment }} has failed but has not been
rolled back.\n VALUE = {{ $value }}\n LABELS = {{ $labels }}"
- alert: KubernetesStatefulsetReplicasMismatch
expr: 'kube_statefulset_status_replicas_ready != kube_statefulset_status_replicas'
for: 10m
labels:
severity: warning
annotations:
summary: Kubernetes StatefulSet replicas mismatch (instance {{ $labels.instance }})
description: "StatefulSet does not match the expected number of replicas.\n VALUE = {{ $value }}\n LABELS = {{ $labels }}"
- alert: KubernetesStatefulsetGenerationMismatch
expr: "kube_statefulset_status_observed_generation != kube_statefulset_metadata_generation"
for: 10m
labels:
severity: critical
annotations:
summary:
Kubernetes StatefulSet generation mismatch ({{ $labels.namespace }}/{{
$labels.statefulset }})
description:
"StatefulSet {{ $labels.namespace }}/{{ $labels.statefulset }} has failed but has not
been rolled back.\n VALUE = {{ $value }}\n LABELS = {{ $labels }}"
- alert: KubernetesDeploymentGenerationMismatch
expr: 'kube_deployment_status_observed_generation != kube_deployment_metadata_generation'
for: 10m
labels:
severity: critical
annotations:
summary: Kubernetes Deployment generation mismatch ({{ $labels.namespace }}/{{ $labels.deployment }})
description: "Deployment {{ $labels.namespace }}/{{ $labels.deployment }} has failed but has not been rolled back.\n VALUE = {{ $value }}\n LABELS = {{ $labels }}"
- alert: KubernetesStatefulsetUpdateNotRolledOut
expr:
"max without (revision) (kube_statefulset_status_current_revision unless
kube_statefulset_status_update_revision) * (kube_statefulset_replicas !=
kube_statefulset_status_replicas_updated)"
for: 10m
labels:
severity: warning
annotations:
summary:
Kubernetes StatefulSet update not rolled out ({{ $labels.namespace }}/{{
$labels.statefulset }})
description:
"StatefulSet {{ $labels.namespace }}/{{ $labels.statefulset }} update has not been
rolled out.\n VALUE = {{ $value }}\n LABELS = {{ $labels }}"
- alert: KubernetesStatefulsetGenerationMismatch
expr: 'kube_statefulset_status_observed_generation != kube_statefulset_metadata_generation'
for: 10m
labels:
severity: critical
annotations:
summary: Kubernetes StatefulSet generation mismatch ({{ $labels.namespace }}/{{ $labels.statefulset }})
description: "StatefulSet {{ $labels.namespace }}/{{ $labels.statefulset }} has failed but has not been rolled back.\n VALUE = {{ $value }}\n LABELS = {{ $labels }}"
- alert: KubernetesDaemonsetRolloutStuck
expr:
"kube_daemonset_status_number_ready / kube_daemonset_status_desired_number_scheduled * 100
< 100 or kube_daemonset_status_desired_number_scheduled -
kube_daemonset_status_current_number_scheduled > 0"
for: 10m
labels:
severity: warning
annotations:
summary:
Kubernetes DaemonSet rollout stuck ({{ $labels.namespace }}/{{ $labels.daemonset }})
description:
"Some Pods of DaemonSet {{ $labels.namespace }}/{{ $labels.daemonset }} are not
scheduled or not ready\n VALUE = {{ $value }}\n LABELS = {{ $labels }}"
- alert: KubernetesStatefulsetUpdateNotRolledOut
expr: 'max without (revision) (kube_statefulset_status_current_revision unless kube_statefulset_status_update_revision) * (kube_statefulset_replicas != kube_statefulset_status_replicas_updated)'
for: 10m
labels:
severity: warning
annotations:
summary: Kubernetes StatefulSet update not rolled out ({{ $labels.namespace }}/{{ $labels.statefulset }})
description: "StatefulSet {{ $labels.namespace }}/{{ $labels.statefulset }} update has not been rolled out.\n VALUE = {{ $value }}\n LABELS = {{ $labels }}"
- alert: KubernetesDaemonsetMisscheduled
expr: "kube_daemonset_status_number_misscheduled > 0"
for: 1m
labels:
severity: critical
annotations:
summary:
Kubernetes DaemonSet misscheduled ({{ $labels.namespace }}/{{ $labels.daemonset }})
description:
"Some Pods of DaemonSet {{ $labels.namespace }}/{{ $labels.daemonset }} are running
where they are not supposed to run\n VALUE = {{ $value }}\n LABELS = {{ $labels }}"
- alert: KubernetesDaemonsetRolloutStuck
expr: 'kube_daemonset_status_number_ready / kube_daemonset_status_desired_number_scheduled * 100 < 100 or kube_daemonset_status_desired_number_scheduled - kube_daemonset_status_current_number_scheduled > 0'
for: 10m
labels:
severity: warning
annotations:
summary: Kubernetes DaemonSet rollout stuck ({{ $labels.namespace }}/{{ $labels.daemonset }})
description: "Some Pods of DaemonSet {{ $labels.namespace }}/{{ $labels.daemonset }} are not scheduled or not ready\n VALUE = {{ $value }}\n LABELS = {{ $labels }}"
- alert: KubernetesCronjobTooLong
expr: "time() - kube_cronjob_next_schedule_time > 3600"
for: 0m
labels:
severity: warning
annotations:
summary: Kubernetes CronJob too long ({{ $labels.namespace }}/{{ $labels.cronjob }})
description:
"CronJob {{ $labels.namespace }}/{{ $labels.cronjob }} is taking more than 1h to
complete.\n VALUE = {{ $value }}\n LABELS = {{ $labels }}"
- alert: KubernetesDaemonsetMisscheduled
expr: 'kube_daemonset_status_number_misscheduled > 0'
for: 1m
labels:
severity: critical
annotations:
summary: Kubernetes DaemonSet misscheduled ({{ $labels.namespace }}/{{ $labels.daemonset }})
description: "Some Pods of DaemonSet {{ $labels.namespace }}/{{ $labels.daemonset }} are running where they are not supposed to run\n VALUE = {{ $value }}\n LABELS = {{ $labels }}"
- alert: KubernetesJobSlowCompletion
expr: "kube_job_spec_completions - kube_job_status_succeeded - kube_job_status_failed > 0"
for: 12h
labels:
severity: critical
annotations:
summary: Kubernetes job slow completion ({{ $labels.namespace }}/{{ $labels.job_name }})
description:
"Kubernetes Job {{ $labels.namespace }}/{{ $labels.job_name }} did not complete in
time.\n VALUE = {{ $value }}\n LABELS = {{ $labels }}"
- alert: KubernetesCronjobTooLong
expr: 'time() - kube_cronjob_next_schedule_time > 3600'
for: 0m
labels:
severity: warning
annotations:
summary: Kubernetes CronJob too long ({{ $labels.namespace }}/{{ $labels.cronjob }})
description: "CronJob {{ $labels.namespace }}/{{ $labels.cronjob }} is taking more than 1h to complete.\n VALUE = {{ $value }}\n LABELS = {{ $labels }}"
- alert: KubernetesApiServerErrors
expr:
'sum(rate(apiserver_request_total{job="apiserver",code=~"^(?:5..)$"}[1m])) /
sum(rate(apiserver_request_total{job="apiserver"}[1m])) * 100 > 3'
for: 2m
labels:
severity: critical
annotations:
summary: Kubernetes API server errors (instance {{ $labels.instance }})
description:
"Kubernetes API server is experiencing high error rate\n VALUE = {{ $value }}\n LABELS
= {{ $labels }}"
- alert: KubernetesJobSlowCompletion
expr: 'kube_job_spec_completions - kube_job_status_succeeded - kube_job_status_failed > 0'
for: 12h
labels:
severity: critical
annotations:
summary: Kubernetes job slow completion ({{ $labels.namespace }}/{{ $labels.job_name }})
description: "Kubernetes Job {{ $labels.namespace }}/{{ $labels.job_name }} did not complete in time.\n VALUE = {{ $value }}\n LABELS = {{ $labels }}"
- alert: KubernetesApiClientErrors
expr:
'(sum(rate(rest_client_requests_total{code=~"(4|5).."}[1m])) by (instance, job) /
sum(rate(rest_client_requests_total[1m])) by (instance, job)) * 100 > 1'
for: 2m
labels:
severity: critical
annotations:
summary: Kubernetes API client errors (instance {{ $labels.instance }})
description:
"Kubernetes API client is experiencing high error rate\n VALUE = {{ $value }}\n LABELS
= {{ $labels }}"
- alert: KubernetesApiServerErrors
expr: 'sum(rate(apiserver_request_total{job="apiserver",code=~"^(?:5..)$"}[1m])) / sum(rate(apiserver_request_total{job="apiserver"}[1m])) * 100 > 3'
for: 2m
labels:
severity: critical
annotations:
summary: Kubernetes API server errors (instance {{ $labels.instance }})
description: "Kubernetes API server is experiencing high error rate\n VALUE = {{ $value }}\n LABELS = {{ $labels }}"
- alert: KubernetesClientCertificateExpiresNextWeek
expr:
'apiserver_client_certificate_expiration_seconds_count{job="apiserver"} > 0 and
histogram_quantile(0.01, sum by (job, le)
(rate(apiserver_client_certificate_expiration_seconds_bucket{job="apiserver"}[5m]))) <
7*24*60*60'
for: 0m
labels:
severity: warning
annotations:
summary: Kubernetes client certificate expires next week (instance {{ $labels.instance }})
description:
"A client certificate used to authenticate to the apiserver is expiring next
week.\n VALUE = {{ $value }}\n LABELS = {{ $labels }}"
- alert: KubernetesApiClientErrors
expr: '(sum(rate(rest_client_requests_total{code=~"(4|5).."}[1m])) by (instance, job) / sum(rate(rest_client_requests_total[1m])) by (instance, job)) * 100 > 1'
for: 2m
labels:
severity: critical
annotations:
summary: Kubernetes API client errors (instance {{ $labels.instance }})
description: "Kubernetes API client is experiencing high error rate\n VALUE = {{ $value }}\n LABELS = {{ $labels }}"
- alert: KubernetesClientCertificateExpiresSoon
expr:
'apiserver_client_certificate_expiration_seconds_count{job="apiserver"} > 0 and
histogram_quantile(0.01, sum by (job, le)
(rate(apiserver_client_certificate_expiration_seconds_bucket{job="apiserver"}[5m]))) <
24*60*60'
for: 0m
labels:
severity: critical
annotations:
summary: Kubernetes client certificate expires soon (instance {{ $labels.instance }})
description:
"A client certificate used to authenticate to the apiserver is expiring in less than
24.0 hours.\n VALUE = {{ $value }}\n LABELS = {{ $labels }}"
- alert: KubernetesClientCertificateExpiresNextWeek
expr: 'apiserver_client_certificate_expiration_seconds_count{job="apiserver"} > 0 and histogram_quantile(0.01, sum by (job, le) (rate(apiserver_client_certificate_expiration_seconds_bucket{job="apiserver"}[5m]))) < 7*24*60*60'
for: 0m
labels:
severity: warning
annotations:
summary: Kubernetes client certificate expires next week (instance {{ $labels.instance }})
description: "A client certificate used to authenticate to the apiserver is expiring next week.\n VALUE = {{ $value }}\n LABELS = {{ $labels }}"
- alert: KubernetesClientCertificateExpiresSoon
expr: 'apiserver_client_certificate_expiration_seconds_count{job="apiserver"} > 0 and histogram_quantile(0.01, sum by (job, le) (rate(apiserver_client_certificate_expiration_seconds_bucket{job="apiserver"}[5m]))) < 24*60*60'
for: 0m
labels:
severity: critical
annotations:
summary: Kubernetes client certificate expires soon (instance {{ $labels.instance }})
description: "A client certificate used to authenticate to the apiserver is expiring in less than 24.0 hours.\n VALUE = {{ $value }}\n LABELS = {{ $labels }}"
- alert: KubernetesApiServerLatency
expr: 'histogram_quantile(0.99, sum(rate(apiserver_request_duration_seconds_bucket{subresource!="log",verb!~"^(?:CONNECT|WATCHLIST|WATCH|PROXY)$"} [10m])) WITHOUT (instance, resource)) > 1'
for: 2m
labels:
severity: warning
annotations:
summary: Kubernetes API server latency (instance {{ $labels.instance }})
description: "Kubernetes API server has a 99th percentile latency of {{ $value }} seconds for {{ $labels.verb }} {{ $labels.resource }}.\n VALUE = {{ $value }}\n LABELS = {{ $labels }}"
- alert: KubernetesApiServerLatency
expr:
'histogram_quantile(0.99,
sum(rate(apiserver_request_duration_seconds_bucket{subresource!="log",verb!~"^(?:CONNECT|WATCHLIST|WATCH|PROXY)$"}
[10m])) WITHOUT (instance, resource)) > 1'
for: 2m
labels:
severity: warning
annotations:
summary: Kubernetes API server latency (instance {{ $labels.instance }})
description:
"Kubernetes API server has a 99th percentile latency of {{ $value }} seconds for {{
$labels.verb }} {{ $labels.resource }}.\n VALUE = {{ $value }}\n LABELS = {{ $labels
}}"

View File

@@ -1,347 +1,508 @@
groups:
- name: NodeExporter
- name: NodeExporter
rules:
- alert: HostOutOfMemory
expr:
'(node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes * 100 < 10) * on(instance)
group_left (nodename) node_uname_info{nodename=~".+"}'
for: 2m
labels:
severity: warning
annotations:
summary: Host out of memory (instance {{ $labels.instance }})
description:
"Node memory is filling up (< 10% left)\n VALUE = {{ $value }}\n LABELS = {{ $labels
}}"
rules:
- alert: HostMemoryUnderMemoryPressure
expr:
'(rate(node_vmstat_pgmajfault[1m]) > 1000) * on(instance) group_left (nodename)
node_uname_info{nodename=~".+"}'
for: 2m
labels:
severity: warning
annotations:
summary: Host memory under memory pressure (instance {{ $labels.instance }})
description:
"The node is under heavy memory pressure. High rate of major page faults\n VALUE = {{
$value }}\n LABELS = {{ $labels }}"
- alert: HostOutOfMemory
expr: '(node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes * 100 < 10) * on(instance) group_left (nodename) node_uname_info{nodename=~".+"}'
for: 2m
labels:
severity: warning
annotations:
summary: Host out of memory (instance {{ $labels.instance }})
description: "Node memory is filling up (< 10% left)\n VALUE = {{ $value }}\n LABELS = {{ $labels }}"
- alert: HostMemoryIsUnderutilized
expr:
'(100 - (avg_over_time(node_memory_MemAvailable_bytes[30m]) / node_memory_MemTotal_bytes *
100) < 20) * on(instance) group_left (nodename) node_uname_info{nodename=~".+"}'
for: 1w
labels:
severity: info
annotations:
summary: Host Memory is underutilized (instance {{ $labels.instance }})
description:
"Node memory is < 20% for 1 week. Consider reducing memory space. (instance {{
$labels.instance }})\n VALUE = {{ $value }}\n LABELS = {{ $labels }}"
- alert: HostMemoryUnderMemoryPressure
expr: '(rate(node_vmstat_pgmajfault[1m]) > 1000) * on(instance) group_left (nodename) node_uname_info{nodename=~".+"}'
for: 2m
labels:
severity: warning
annotations:
summary: Host memory under memory pressure (instance {{ $labels.instance }})
description: "The node is under heavy memory pressure. High rate of major page faults\n VALUE = {{ $value }}\n LABELS = {{ $labels }}"
- alert: HostUnusualNetworkThroughputIn
expr:
'(sum by (instance) (rate(node_network_receive_bytes_total[2m])) / 1024 / 1024 > 100) *
on(instance) group_left (nodename) node_uname_info{nodename=~".+"}'
for: 5m
labels:
severity: warning
annotations:
summary: Host unusual network throughput in (instance {{ $labels.instance }})
description:
"Host network interfaces are probably receiving too much data (> 100 MB/s)\n VALUE = {{
$value }}\n LABELS = {{ $labels }}"
- alert: HostMemoryIsUnderutilized
expr: '(100 - (avg_over_time(node_memory_MemAvailable_bytes[30m]) / node_memory_MemTotal_bytes * 100) < 20) * on(instance) group_left (nodename) node_uname_info{nodename=~".+"}'
for: 1w
labels:
severity: info
annotations:
summary: Host Memory is underutilized (instance {{ $labels.instance }})
description: "Node memory is < 20% for 1 week. Consider reducing memory space. (instance {{ $labels.instance }})\n VALUE = {{ $value }}\n LABELS = {{ $labels }}"
- alert: HostUnusualNetworkThroughputOut
expr:
'(sum by (instance) (rate(node_network_transmit_bytes_total[2m])) / 1024 / 1024 > 100) *
on(instance) group_left (nodename) node_uname_info{nodename=~".+"}'
for: 5m
labels:
severity: warning
annotations:
summary: Host unusual network throughput out (instance {{ $labels.instance }})
description:
"Host network interfaces are probably sending too much data (> 100 MB/s)\n VALUE = {{
$value }}\n LABELS = {{ $labels }}"
- alert: HostUnusualNetworkThroughputIn
expr: '(sum by (instance) (rate(node_network_receive_bytes_total[2m])) / 1024 / 1024 > 100) * on(instance) group_left (nodename) node_uname_info{nodename=~".+"}'
for: 5m
labels:
severity: warning
annotations:
summary: Host unusual network throughput in (instance {{ $labels.instance }})
description: "Host network interfaces are probably receiving too much data (> 100 MB/s)\n VALUE = {{ $value }}\n LABELS = {{ $labels }}"
- alert: HostUnusualDiskReadRate
expr:
'(sum by (instance) (rate(node_disk_read_bytes_total[2m])) / 1024 / 1024 > 50) *
on(instance) group_left (nodename) node_uname_info{nodename=~".+"}'
for: 5m
labels:
severity: warning
annotations:
summary: Host unusual disk read rate (instance {{ $labels.instance }})
description:
"Disk is probably reading too much data (> 50 MB/s)\n VALUE = {{ $value }}\n LABELS =
{{ $labels }}"
- alert: HostUnusualNetworkThroughputOut
expr: '(sum by (instance) (rate(node_network_transmit_bytes_total[2m])) / 1024 / 1024 > 100) * on(instance) group_left (nodename) node_uname_info{nodename=~".+"}'
for: 5m
labels:
severity: warning
annotations:
summary: Host unusual network throughput out (instance {{ $labels.instance }})
description: "Host network interfaces are probably sending too much data (> 100 MB/s)\n VALUE = {{ $value }}\n LABELS = {{ $labels }}"
- alert: HostUnusualDiskWriteRate
expr:
'(sum by (instance) (rate(node_disk_written_bytes_total[2m])) / 1024 / 1024 > 50) *
on(instance) group_left (nodename) node_uname_info{nodename=~".+"}'
for: 2m
labels:
severity: warning
annotations:
summary: Host unusual disk write rate (instance {{ $labels.instance }})
description:
"Disk is probably writing too much data (> 50 MB/s)\n VALUE = {{ $value }}\n LABELS =
{{ $labels }}"
- alert: HostUnusualDiskReadRate
expr: '(sum by (instance) (rate(node_disk_read_bytes_total[2m])) / 1024 / 1024 > 50) * on(instance) group_left (nodename) node_uname_info{nodename=~".+"}'
for: 5m
labels:
severity: warning
annotations:
summary: Host unusual disk read rate (instance {{ $labels.instance }})
description: "Disk is probably reading too much data (> 50 MB/s)\n VALUE = {{ $value }}\n LABELS = {{ $labels }}"
- alert: HostOutOfDiskSpace
expr:
'((node_filesystem_avail_bytes * 100) / node_filesystem_size_bytes < 10 and ON (instance,
device, mountpoint) node_filesystem_readonly == 0) * on(instance) group_left (nodename)
node_uname_info{nodename=~".+"}'
for: 2m
labels:
severity: warning
annotations:
summary: Host out of disk space (instance {{ $labels.instance }})
description:
"Disk is almost full (< 10% left)\n VALUE = {{ $value }}\n LABELS = {{ $labels }}"
- alert: HostUnusualDiskWriteRate
expr: '(sum by (instance) (rate(node_disk_written_bytes_total[2m])) / 1024 / 1024 > 50) * on(instance) group_left (nodename) node_uname_info{nodename=~".+"}'
for: 2m
labels:
severity: warning
annotations:
summary: Host unusual disk write rate (instance {{ $labels.instance }})
description: "Disk is probably writing too much data (> 50 MB/s)\n VALUE = {{ $value }}\n LABELS = {{ $labels }}"
- alert: HostDiskWillFillIn24Hours
expr:
'((node_filesystem_avail_bytes * 100) / node_filesystem_size_bytes < 10 and ON (instance,
device, mountpoint) predict_linear(node_filesystem_avail_bytes{fstype!~"tmpfs"}[1h], 24 *
3600) < 0 and ON (instance, device, mountpoint) node_filesystem_readonly == 0) *
on(instance) group_left (nodename) node_uname_info{nodename=~".+"}'
for: 2m
labels:
severity: warning
annotations:
summary: Host disk will fill in 24 hours (instance {{ $labels.instance }})
description:
"Filesystem is predicted to run out of space within the next 24 hours at current write
rate\n VALUE = {{ $value }}\n LABELS = {{ $labels }}"
- alert: HostOutOfDiskSpace
expr: '((node_filesystem_avail_bytes * 100) / node_filesystem_size_bytes < 10 and ON (instance, device, mountpoint) node_filesystem_readonly == 0) * on(instance) group_left (nodename) node_uname_info{nodename=~".+"}'
for: 2m
labels:
severity: warning
annotations:
summary: Host out of disk space (instance {{ $labels.instance }})
description: "Disk is almost full (< 10% left)\n VALUE = {{ $value }}\n LABELS = {{ $labels }}"
- alert: HostOutOfInodes
expr:
'(node_filesystem_files_free{fstype!="msdosfs"} / node_filesystem_files{fstype!="msdosfs"}
* 100 < 10 and ON (instance, device, mountpoint) node_filesystem_readonly == 0) *
on(instance) group_left (nodename) node_uname_info{nodename=~".+"}'
for: 2m
labels:
severity: warning
annotations:
summary: Host out of inodes (instance {{ $labels.instance }})
description:
"Disk is almost running out of available inodes (< 10% left)\n VALUE = {{ $value
}}\n LABELS = {{ $labels }}"
- alert: HostDiskWillFillIn24Hours
expr: '((node_filesystem_avail_bytes * 100) / node_filesystem_size_bytes < 10 and ON (instance, device, mountpoint) predict_linear(node_filesystem_avail_bytes{fstype!~"tmpfs"}[1h], 24 * 3600) < 0 and ON (instance, device, mountpoint) node_filesystem_readonly == 0) * on(instance) group_left (nodename) node_uname_info{nodename=~".+"}'
for: 2m
labels:
severity: warning
annotations:
summary: Host disk will fill in 24 hours (instance {{ $labels.instance }})
description: "Filesystem is predicted to run out of space within the next 24 hours at current write rate\n VALUE = {{ $value }}\n LABELS = {{ $labels }}"
- alert: HostFilesystemDeviceError
expr: "node_filesystem_device_error == 1"
for: 0m
labels:
severity: critical
annotations:
summary: Host filesystem device error (instance {{ $labels.instance }})
description:
"{{ $labels.instance }}: Device error with the {{ $labels.mountpoint }}
filesystem\n VALUE = {{ $value }}\n LABELS = {{ $labels }}"
- alert: HostOutOfInodes
expr: '(node_filesystem_files_free{fstype!="msdosfs"} / node_filesystem_files{fstype!="msdosfs"} * 100 < 10 and ON (instance, device, mountpoint) node_filesystem_readonly == 0) * on(instance) group_left (nodename) node_uname_info{nodename=~".+"}'
for: 2m
labels:
severity: warning
annotations:
summary: Host out of inodes (instance {{ $labels.instance }})
description: "Disk is almost running out of available inodes (< 10% left)\n VALUE = {{ $value }}\n LABELS = {{ $labels }}"
- alert: HostInodesWillFillIn24Hours
expr:
'(node_filesystem_files_free{fstype!="msdosfs"} / node_filesystem_files{fstype!="msdosfs"}
* 100 < 10 and predict_linear(node_filesystem_files_free{fstype!="msdosfs"}[1h], 24 *
3600) < 0 and ON (instance, device, mountpoint)
node_filesystem_readonly{fstype!="msdosfs"} == 0) * on(instance) group_left (nodename)
node_uname_info{nodename=~".+"}'
for: 2m
labels:
severity: warning
annotations:
summary: Host inodes will fill in 24 hours (instance {{ $labels.instance }})
description:
"Filesystem is predicted to run out of inodes within the next 24 hours at current write
rate\n VALUE = {{ $value }}\n LABELS = {{ $labels }}"
- alert: HostFilesystemDeviceError
expr: 'node_filesystem_device_error == 1'
for: 0m
labels:
severity: critical
annotations:
summary: Host filesystem device error (instance {{ $labels.instance }})
description: "{{ $labels.instance }}: Device error with the {{ $labels.mountpoint }} filesystem\n VALUE = {{ $value }}\n LABELS = {{ $labels }}"
- alert: HostUnusualDiskReadLatency
expr:
'(rate(node_disk_read_time_seconds_total[1m]) / rate(node_disk_reads_completed_total[1m])
> 0.1 and rate(node_disk_reads_completed_total[1m]) > 0) * on(instance) group_left
(nodename) node_uname_info{nodename=~".+"}'
for: 2m
labels:
severity: warning
annotations:
summary: Host unusual disk read latency (instance {{ $labels.instance }})
description:
"Disk latency is growing (read operations > 100ms)\n VALUE = {{ $value }}\n LABELS =
{{ $labels }}"
- alert: HostInodesWillFillIn24Hours
expr: '(node_filesystem_files_free{fstype!="msdosfs"} / node_filesystem_files{fstype!="msdosfs"} * 100 < 10 and predict_linear(node_filesystem_files_free{fstype!="msdosfs"}[1h], 24 * 3600) < 0 and ON (instance, device, mountpoint) node_filesystem_readonly{fstype!="msdosfs"} == 0) * on(instance) group_left (nodename) node_uname_info{nodename=~".+"}'
for: 2m
labels:
severity: warning
annotations:
summary: Host inodes will fill in 24 hours (instance {{ $labels.instance }})
description: "Filesystem is predicted to run out of inodes within the next 24 hours at current write rate\n VALUE = {{ $value }}\n LABELS = {{ $labels }}"
- alert: HostUnusualDiskWriteLatency
expr:
'(rate(node_disk_write_time_seconds_total[1m]) /
rate(node_disk_writes_completed_total[1m]) > 0.1 and
rate(node_disk_writes_completed_total[1m]) > 0) * on(instance) group_left (nodename)
node_uname_info{nodename=~".+"}'
for: 2m
labels:
severity: warning
annotations:
summary: Host unusual disk write latency (instance {{ $labels.instance }})
description:
"Disk latency is growing (write operations > 100ms)\n VALUE = {{ $value }}\n LABELS =
{{ $labels }}"
- alert: HostUnusualDiskReadLatency
expr: '(rate(node_disk_read_time_seconds_total[1m]) / rate(node_disk_reads_completed_total[1m]) > 0.1 and rate(node_disk_reads_completed_total[1m]) > 0) * on(instance) group_left (nodename) node_uname_info{nodename=~".+"}'
for: 2m
labels:
severity: warning
annotations:
summary: Host unusual disk read latency (instance {{ $labels.instance }})
description: "Disk latency is growing (read operations > 100ms)\n VALUE = {{ $value }}\n LABELS = {{ $labels }}"
- alert: HostHighCpuLoad
expr:
'(sum by (instance) (avg by (mode, instance)
(rate(node_cpu_seconds_total{mode!="idle"}[2m]))) > 0.8) * on(instance) group_left
(nodename) node_uname_info{nodename=~".+"}'
for: 10m
labels:
severity: warning
annotations:
summary: Host high CPU load (instance {{ $labels.instance }})
description: "CPU load is > 80%\n VALUE = {{ $value }}\n LABELS = {{ $labels }}"
- alert: HostUnusualDiskWriteLatency
expr: '(rate(node_disk_write_time_seconds_total[1m]) / rate(node_disk_writes_completed_total[1m]) > 0.1 and rate(node_disk_writes_completed_total[1m]) > 0) * on(instance) group_left (nodename) node_uname_info{nodename=~".+"}'
for: 2m
labels:
severity: warning
annotations:
summary: Host unusual disk write latency (instance {{ $labels.instance }})
description: "Disk latency is growing (write operations > 100ms)\n VALUE = {{ $value }}\n LABELS = {{ $labels }}"
- alert: HostCpuIsUnderutilized
expr:
'(100 - (rate(node_cpu_seconds_total{mode="idle"}[30m]) * 100) < 20) * on(instance)
group_left (nodename) node_uname_info{nodename=~".+"}'
for: 1w
labels:
severity: info
annotations:
summary: Host CPU is underutilized (instance {{ $labels.instance }})
description:
"CPU load is < 20% for 1 week. Consider reducing the number of CPUs.\n VALUE = {{
$value }}\n LABELS = {{ $labels }}"
- alert: HostHighCpuLoad
expr: '(sum by (instance) (avg by (mode, instance) (rate(node_cpu_seconds_total{mode!="idle"}[2m]))) > 0.8) * on(instance) group_left (nodename) node_uname_info{nodename=~".+"}'
for: 10m
labels:
severity: warning
annotations:
summary: Host high CPU load (instance {{ $labels.instance }})
description: "CPU load is > 80%\n VALUE = {{ $value }}\n LABELS = {{ $labels }}"
- alert: HostCpuStealNoisyNeighbor
expr:
'(avg by(instance) (rate(node_cpu_seconds_total{mode="steal"}[5m])) * 100 > 10) *
on(instance) group_left (nodename) node_uname_info{nodename=~".+"}'
for: 0m
labels:
severity: warning
annotations:
summary: Host CPU steal noisy neighbor (instance {{ $labels.instance }})
description:
"CPU steal is > 10%. A noisy neighbor is killing VM performances or a spot instance may
be out of credit.\n VALUE = {{ $value }}\n LABELS = {{ $labels }}"
- alert: HostCpuIsUnderutilized
expr: '(100 - (rate(node_cpu_seconds_total{mode="idle"}[30m]) * 100) < 20) * on(instance) group_left (nodename) node_uname_info{nodename=~".+"}'
for: 1w
labels:
severity: info
annotations:
summary: Host CPU is underutilized (instance {{ $labels.instance }})
description: "CPU load is < 20% for 1 week. Consider reducing the number of CPUs.\n VALUE = {{ $value }}\n LABELS = {{ $labels }}"
- alert: HostCpuHighIowait
expr:
'(avg by (instance) (rate(node_cpu_seconds_total{mode="iowait"}[5m])) * 100 > 10) *
on(instance) group_left (nodename) node_uname_info{nodename=~".+"}'
for: 0m
labels:
severity: warning
annotations:
summary: Host CPU high iowait (instance {{ $labels.instance }})
description:
"CPU iowait > 10%. A high iowait means that you are disk or network bound.\n VALUE = {{
$value }}\n LABELS = {{ $labels }}"
- alert: HostCpuStealNoisyNeighbor
expr: '(avg by(instance) (rate(node_cpu_seconds_total{mode="steal"}[5m])) * 100 > 10) * on(instance) group_left (nodename) node_uname_info{nodename=~".+"}'
for: 0m
labels:
severity: warning
annotations:
summary: Host CPU steal noisy neighbor (instance {{ $labels.instance }})
description: "CPU steal is > 10%. A noisy neighbor is killing VM performances or a spot instance may be out of credit.\n VALUE = {{ $value }}\n LABELS = {{ $labels }}"
- alert: HostUnusualDiskIo
expr:
'(rate(node_disk_io_time_seconds_total[1m]) > 0.5) * on(instance) group_left (nodename)
node_uname_info{nodename=~".+"}'
for: 5m
labels:
severity: warning
annotations:
summary: Host unusual disk IO (instance {{ $labels.instance }})
description:
"Time spent in IO is too high on {{ $labels.instance }}. Check storage for
issues.\n VALUE = {{ $value }}\n LABELS = {{ $labels }}"
- alert: HostCpuHighIowait
expr: '(avg by (instance) (rate(node_cpu_seconds_total{mode="iowait"}[5m])) * 100 > 10) * on(instance) group_left (nodename) node_uname_info{nodename=~".+"}'
for: 0m
labels:
severity: warning
annotations:
summary: Host CPU high iowait (instance {{ $labels.instance }})
description: "CPU iowait > 10%. A high iowait means that you are disk or network bound.\n VALUE = {{ $value }}\n LABELS = {{ $labels }}"
- alert: HostContextSwitching
expr:
'((rate(node_context_switches_total[5m])) / (count without(cpu, mode)
(node_cpu_seconds_total{mode="idle"})) > 10000) * on(instance) group_left (nodename)
node_uname_info{nodename=~".+"}'
for: 0m
labels:
severity: warning
annotations:
summary: Host context switching (instance {{ $labels.instance }})
description:
"Context switching is growing on the node (> 10000 / CPU / s)\n VALUE = {{ $value
}}\n LABELS = {{ $labels }}"
- alert: HostUnusualDiskIo
expr: '(rate(node_disk_io_time_seconds_total[1m]) > 0.5) * on(instance) group_left (nodename) node_uname_info{nodename=~".+"}'
for: 5m
labels:
severity: warning
annotations:
summary: Host unusual disk IO (instance {{ $labels.instance }})
description: "Time spent in IO is too high on {{ $labels.instance }}. Check storage for issues.\n VALUE = {{ $value }}\n LABELS = {{ $labels }}"
- alert: HostSwapIsFillingUp
expr:
'((1 - (node_memory_SwapFree_bytes / node_memory_SwapTotal_bytes)) * 100 > 80) *
on(instance) group_left (nodename) node_uname_info{nodename=~".+"}'
for: 2m
labels:
severity: warning
annotations:
summary: Host swap is filling up (instance {{ $labels.instance }})
description: "Swap is filling up (>80%)\n VALUE = {{ $value }}\n LABELS = {{ $labels }}"
- alert: HostContextSwitching
expr: '((rate(node_context_switches_total[5m])) / (count without(cpu, mode) (node_cpu_seconds_total{mode="idle"})) > 10000) * on(instance) group_left (nodename) node_uname_info{nodename=~".+"}'
for: 0m
labels:
severity: warning
annotations:
summary: Host context switching (instance {{ $labels.instance }})
description: "Context switching is growing on the node (> 10000 / CPU / s)\n VALUE = {{ $value }}\n LABELS = {{ $labels }}"
- alert: HostSystemdServiceCrashed
expr:
'(node_systemd_unit_state{state="failed"} == 1) * on(instance) group_left (nodename)
node_uname_info{nodename=~".+"}'
for: 0m
labels:
severity: warning
annotations:
summary: Host systemd service crashed (instance {{ $labels.instance }})
description: "systemd service crashed\n VALUE = {{ $value }}\n LABELS = {{ $labels }}"
- alert: HostSwapIsFillingUp
expr: '((1 - (node_memory_SwapFree_bytes / node_memory_SwapTotal_bytes)) * 100 > 80) * on(instance) group_left (nodename) node_uname_info{nodename=~".+"}'
for: 2m
labels:
severity: warning
annotations:
summary: Host swap is filling up (instance {{ $labels.instance }})
description: "Swap is filling up (>80%)\n VALUE = {{ $value }}\n LABELS = {{ $labels }}"
- alert: HostPhysicalComponentTooHot
expr:
'((node_hwmon_temp_celsius * ignoring(label) group_left(instance, job, node, sensor)
node_hwmon_sensor_label{label!="tctl"} > 75)) * on(instance) group_left (nodename)
node_uname_info{nodename=~".+"}'
for: 5m
labels:
severity: warning
annotations:
summary: Host physical component too hot (instance {{ $labels.instance }})
description:
"Physical hardware component too hot\n VALUE = {{ $value }}\n LABELS = {{ $labels }}"
- alert: HostSystemdServiceCrashed
expr: '(node_systemd_unit_state{state="failed"} == 1) * on(instance) group_left (nodename) node_uname_info{nodename=~".+"}'
for: 0m
labels:
severity: warning
annotations:
summary: Host systemd service crashed (instance {{ $labels.instance }})
description: "systemd service crashed\n VALUE = {{ $value }}\n LABELS = {{ $labels }}"
- alert: HostNodeOvertemperatureAlarm
expr:
'(node_hwmon_temp_crit_alarm_celsius == 1) * on(instance) group_left (nodename)
node_uname_info{nodename=~".+"}'
for: 0m
labels:
severity: critical
annotations:
summary: Host node overtemperature alarm (instance {{ $labels.instance }})
description:
"Physical node temperature alarm triggered\n VALUE = {{ $value }}\n LABELS = {{
$labels }}"
- alert: HostPhysicalComponentTooHot
expr: '((node_hwmon_temp_celsius * ignoring(label) group_left(instance, job, node, sensor) node_hwmon_sensor_label{label!="tctl"} > 75)) * on(instance) group_left (nodename) node_uname_info{nodename=~".+"}'
for: 5m
labels:
severity: warning
annotations:
summary: Host physical component too hot (instance {{ $labels.instance }})
description: "Physical hardware component too hot\n VALUE = {{ $value }}\n LABELS = {{ $labels }}"
- alert: HostRaidArrayGotInactive
expr:
'(node_md_state{state="inactive"} > 0) * on(instance) group_left (nodename)
node_uname_info{nodename=~".+"}'
for: 0m
labels:
severity: critical
annotations:
summary: Host RAID array got inactive (instance {{ $labels.instance }})
description:
"RAID array {{ $labels.device }} is in a degraded state due to one or more disk
failures. The number of spare drives is insufficient to fix the issue
automatically.\n VALUE = {{ $value }}\n LABELS = {{ $labels }}"
- alert: HostNodeOvertemperatureAlarm
expr: '(node_hwmon_temp_crit_alarm_celsius == 1) * on(instance) group_left (nodename) node_uname_info{nodename=~".+"}'
for: 0m
labels:
severity: critical
annotations:
summary: Host node overtemperature alarm (instance {{ $labels.instance }})
description: "Physical node temperature alarm triggered\n VALUE = {{ $value }}\n LABELS = {{ $labels }}"
- alert: HostRaidDiskFailure
expr:
'(node_md_disks{state="failed"} > 0) * on(instance) group_left (nodename)
node_uname_info{nodename=~".+"}'
for: 2m
labels:
severity: warning
annotations:
summary: Host RAID disk failure (instance {{ $labels.instance }})
description:
"At least one device in RAID array on {{ $labels.instance }} failed. Array {{
$labels.md_device }} needs attention and possibly a disk swap\n VALUE = {{ $value
}}\n LABELS = {{ $labels }}"
- alert: HostRaidArrayGotInactive
expr: '(node_md_state{state="inactive"} > 0) * on(instance) group_left (nodename) node_uname_info{nodename=~".+"}'
for: 0m
labels:
severity: critical
annotations:
summary: Host RAID array got inactive (instance {{ $labels.instance }})
description: "RAID array {{ $labels.device }} is in a degraded state due to one or more disk failures. The number of spare drives is insufficient to fix the issue automatically.\n VALUE = {{ $value }}\n LABELS = {{ $labels }}"
- alert: HostKernelVersionDeviations
expr:
'(count(sum(label_replace(node_uname_info, "kernel", "$1", "release",
"([0-9]+.[0-9]+.[0-9]+).*")) by (kernel)) > 1) * on(instance) group_left (nodename)
node_uname_info{nodename=~".+"}'
for: 6h
labels:
severity: warning
annotations:
summary: Host kernel version deviations (instance {{ $labels.instance }})
description:
"Different kernel versions are running\n VALUE = {{ $value }}\n LABELS = {{ $labels }}"
- alert: HostRaidDiskFailure
expr: '(node_md_disks{state="failed"} > 0) * on(instance) group_left (nodename) node_uname_info{nodename=~".+"}'
for: 2m
labels:
severity: warning
annotations:
summary: Host RAID disk failure (instance {{ $labels.instance }})
description: "At least one device in RAID array on {{ $labels.instance }} failed. Array {{ $labels.md_device }} needs attention and possibly a disk swap\n VALUE = {{ $value }}\n LABELS = {{ $labels }}"
- alert: HostOomKillDetected
expr:
'(increase(node_vmstat_oom_kill[1m]) > 0) * on(instance) group_left (nodename)
node_uname_info{nodename=~".+"}'
for: 0m
labels:
severity: warning
annotations:
summary: Host OOM kill detected (instance {{ $labels.instance }})
description: "OOM kill detected\n VALUE = {{ $value }}\n LABELS = {{ $labels }}"
- alert: HostKernelVersionDeviations
expr: '(count(sum(label_replace(node_uname_info, "kernel", "$1", "release", "([0-9]+.[0-9]+.[0-9]+).*")) by (kernel)) > 1) * on(instance) group_left (nodename) node_uname_info{nodename=~".+"}'
for: 6h
labels:
severity: warning
annotations:
summary: Host kernel version deviations (instance {{ $labels.instance }})
description: "Different kernel versions are running\n VALUE = {{ $value }}\n LABELS = {{ $labels }}"
- alert: HostEdacCorrectableErrorsDetected
expr:
'(increase(node_edac_correctable_errors_total[1m]) > 0) * on(instance) group_left
(nodename) node_uname_info{nodename=~".+"}'
for: 0m
labels:
severity: info
annotations:
summary: Host EDAC Correctable Errors detected (instance {{ $labels.instance }})
description:
"Host {{ $labels.instance }} has had {{ printf \"%.0f\" $value }} correctable memory
errors reported by EDAC in the last 5 minutes.\n VALUE = {{ $value }}\n LABELS = {{
$labels }}"
- alert: HostOomKillDetected
expr: '(increase(node_vmstat_oom_kill[1m]) > 0) * on(instance) group_left (nodename) node_uname_info{nodename=~".+"}'
for: 0m
labels:
severity: warning
annotations:
summary: Host OOM kill detected (instance {{ $labels.instance }})
description: "OOM kill detected\n VALUE = {{ $value }}\n LABELS = {{ $labels }}"
- alert: HostEdacUncorrectableErrorsDetected
expr:
'(node_edac_uncorrectable_errors_total > 0) * on(instance) group_left (nodename)
node_uname_info{nodename=~".+"}'
for: 0m
labels:
severity: warning
annotations:
summary: Host EDAC Uncorrectable Errors detected (instance {{ $labels.instance }})
description:
"Host {{ $labels.instance }} has had {{ printf \"%.0f\" $value }} uncorrectable memory
errors reported by EDAC in the last 5 minutes.\n VALUE = {{ $value }}\n LABELS = {{
$labels }}"
- alert: HostEdacCorrectableErrorsDetected
expr: '(increase(node_edac_correctable_errors_total[1m]) > 0) * on(instance) group_left (nodename) node_uname_info{nodename=~".+"}'
for: 0m
labels:
severity: info
annotations:
summary: Host EDAC Correctable Errors detected (instance {{ $labels.instance }})
description: "Host {{ $labels.instance }} has had {{ printf \"%.0f\" $value }} correctable memory errors reported by EDAC in the last 5 minutes.\n VALUE = {{ $value }}\n LABELS = {{ $labels }}"
- alert: HostNetworkReceiveErrors
expr:
'(rate(node_network_receive_errs_total[2m]) / rate(node_network_receive_packets_total[2m])
> 0.01) * on(instance) group_left (nodename) node_uname_info{nodename=~".+"}'
for: 2m
labels:
severity: warning
annotations:
summary: Host Network Receive Errors (instance {{ $labels.instance }})
description:
"Host {{ $labels.instance }} interface {{ $labels.device }} has encountered {{ printf
\"%.0f\" $value }} receive errors in the last two minutes.\n VALUE = {{ $value
}}\n LABELS = {{ $labels }}"
- alert: HostEdacUncorrectableErrorsDetected
expr: '(node_edac_uncorrectable_errors_total > 0) * on(instance) group_left (nodename) node_uname_info{nodename=~".+"}'
for: 0m
labels:
severity: warning
annotations:
summary: Host EDAC Uncorrectable Errors detected (instance {{ $labels.instance }})
description: "Host {{ $labels.instance }} has had {{ printf \"%.0f\" $value }} uncorrectable memory errors reported by EDAC in the last 5 minutes.\n VALUE = {{ $value }}\n LABELS = {{ $labels }}"
- alert: HostNetworkTransmitErrors
expr:
'(rate(node_network_transmit_errs_total[2m]) /
rate(node_network_transmit_packets_total[2m]) > 0.01) * on(instance) group_left (nodename)
node_uname_info{nodename=~".+"}'
for: 2m
labels:
severity: warning
annotations:
summary: Host Network Transmit Errors (instance {{ $labels.instance }})
description:
"Host {{ $labels.instance }} interface {{ $labels.device }} has encountered {{ printf
\"%.0f\" $value }} transmit errors in the last two minutes.\n VALUE = {{ $value
}}\n LABELS = {{ $labels }}"
- alert: HostNetworkReceiveErrors
expr: '(rate(node_network_receive_errs_total[2m]) / rate(node_network_receive_packets_total[2m]) > 0.01) * on(instance) group_left (nodename) node_uname_info{nodename=~".+"}'
for: 2m
labels:
severity: warning
annotations:
summary: Host Network Receive Errors (instance {{ $labels.instance }})
description: "Host {{ $labels.instance }} interface {{ $labels.device }} has encountered {{ printf \"%.0f\" $value }} receive errors in the last two minutes.\n VALUE = {{ $value }}\n LABELS = {{ $labels }}"
- alert: HostNetworkInterfaceSaturated
expr:
'((rate(node_network_receive_bytes_total{device!~"^tap.*|^vnet.*|^veth.*|^tun.*"}[1m]) +
rate(node_network_transmit_bytes_total{device!~"^tap.*|^vnet.*|^veth.*|^tun.*"}[1m])) /
node_network_speed_bytes{device!~"^tap.*|^vnet.*|^veth.*|^tun.*"} > 0.8 < 10000) *
on(instance) group_left (nodename) node_uname_info{nodename=~".+"}'
for: 1m
labels:
severity: warning
annotations:
summary: Host Network Interface Saturated (instance {{ $labels.instance }})
description:
"The network interface \"{{ $labels.device }}\" on \"{{ $labels.instance }}\" is getting
overloaded.\n VALUE = {{ $value }}\n LABELS = {{ $labels }}"
- alert: HostNetworkTransmitErrors
expr: '(rate(node_network_transmit_errs_total[2m]) / rate(node_network_transmit_packets_total[2m]) > 0.01) * on(instance) group_left (nodename) node_uname_info{nodename=~".+"}'
for: 2m
labels:
severity: warning
annotations:
summary: Host Network Transmit Errors (instance {{ $labels.instance }})
description: "Host {{ $labels.instance }} interface {{ $labels.device }} has encountered {{ printf \"%.0f\" $value }} transmit errors in the last two minutes.\n VALUE = {{ $value }}\n LABELS = {{ $labels }}"
- alert: HostNetworkBondDegraded
expr:
'((node_bonding_active - node_bonding_slaves) != 0) * on(instance) group_left (nodename)
node_uname_info{nodename=~".+"}'
for: 2m
labels:
severity: warning
annotations:
summary: Host Network Bond Degraded (instance {{ $labels.instance }})
description:
"Bond \"{{ $labels.device }}\" degraded on \"{{ $labels.instance }}\".\n VALUE = {{
$value }}\n LABELS = {{ $labels }}"
- alert: HostNetworkInterfaceSaturated
expr: '((rate(node_network_receive_bytes_total{device!~"^tap.*|^vnet.*|^veth.*|^tun.*"}[1m]) + rate(node_network_transmit_bytes_total{device!~"^tap.*|^vnet.*|^veth.*|^tun.*"}[1m])) / node_network_speed_bytes{device!~"^tap.*|^vnet.*|^veth.*|^tun.*"} > 0.8 < 10000) * on(instance) group_left (nodename) node_uname_info{nodename=~".+"}'
for: 1m
labels:
severity: warning
annotations:
summary: Host Network Interface Saturated (instance {{ $labels.instance }})
description: "The network interface \"{{ $labels.device }}\" on \"{{ $labels.instance }}\" is getting overloaded.\n VALUE = {{ $value }}\n LABELS = {{ $labels }}"
- alert: HostConntrackLimit
expr:
'(node_nf_conntrack_entries / node_nf_conntrack_entries_limit > 0.8) * on(instance)
group_left (nodename) node_uname_info{nodename=~".+"}'
for: 5m
labels:
severity: warning
annotations:
summary: Host conntrack limit (instance {{ $labels.instance }})
description:
"The number of conntrack is approaching limit\n VALUE = {{ $value }}\n LABELS = {{
$labels }}"
- alert: HostNetworkBondDegraded
expr: '((node_bonding_active - node_bonding_slaves) != 0) * on(instance) group_left (nodename) node_uname_info{nodename=~".+"}'
for: 2m
labels:
severity: warning
annotations:
summary: Host Network Bond Degraded (instance {{ $labels.instance }})
description: "Bond \"{{ $labels.device }}\" degraded on \"{{ $labels.instance }}\".\n VALUE = {{ $value }}\n LABELS = {{ $labels }}"
- alert: HostClockSkew
expr:
'((node_timex_offset_seconds > 0.05 and deriv(node_timex_offset_seconds[5m]) >= 0) or
(node_timex_offset_seconds < -0.05 and deriv(node_timex_offset_seconds[5m]) <= 0)) *
on(instance) group_left (nodename) node_uname_info{nodename=~".+"}'
for: 10m
labels:
severity: warning
annotations:
summary: Host clock skew (instance {{ $labels.instance }})
description:
"Clock skew detected. Clock is out of sync. Ensure NTP is configured correctly on this
host.\n VALUE = {{ $value }}\n LABELS = {{ $labels }}"
- alert: HostConntrackLimit
expr: '(node_nf_conntrack_entries / node_nf_conntrack_entries_limit > 0.8) * on(instance) group_left (nodename) node_uname_info{nodename=~".+"}'
for: 5m
labels:
severity: warning
annotations:
summary: Host conntrack limit (instance {{ $labels.instance }})
description: "The number of conntrack is approaching limit\n VALUE = {{ $value }}\n LABELS = {{ $labels }}"
- alert: HostClockNotSynchronising
expr:
'(min_over_time(node_timex_sync_status[1m]) == 0 and node_timex_maxerror_seconds >= 16) *
on(instance) group_left (nodename) node_uname_info{nodename=~".+"}'
for: 2m
labels:
severity: warning
annotations:
summary: Host clock not synchronising (instance {{ $labels.instance }})
description:
"Clock not synchronising. Ensure NTP is configured on this host.\n VALUE = {{ $value
}}\n LABELS = {{ $labels }}"
- alert: HostClockSkew
expr: '((node_timex_offset_seconds > 0.05 and deriv(node_timex_offset_seconds[5m]) >= 0) or (node_timex_offset_seconds < -0.05 and deriv(node_timex_offset_seconds[5m]) <= 0)) * on(instance) group_left (nodename) node_uname_info{nodename=~".+"}'
for: 10m
labels:
severity: warning
annotations:
summary: Host clock skew (instance {{ $labels.instance }})
description: "Clock skew detected. Clock is out of sync. Ensure NTP is configured correctly on this host.\n VALUE = {{ $value }}\n LABELS = {{ $labels }}"
- alert: HostClockNotSynchronising
expr: '(min_over_time(node_timex_sync_status[1m]) == 0 and node_timex_maxerror_seconds >= 16) * on(instance) group_left (nodename) node_uname_info{nodename=~".+"}'
for: 2m
labels:
severity: warning
annotations:
summary: Host clock not synchronising (instance {{ $labels.instance }})
description: "Clock not synchronising. Ensure NTP is configured on this host.\n VALUE = {{ $value }}\n LABELS = {{ $labels }}"
- alert: HostRequiresReboot
expr: '(node_reboot_required > 0) * on(instance) group_left (nodename) node_uname_info{nodename=~".+"}'
for: 4h
labels:
severity: info
annotations:
summary: Host requires reboot (instance {{ $labels.instance }})
description: "{{ $labels.instance }} requires a reboot.\n VALUE = {{ $value }}\n LABELS = {{ $labels }}"
- alert: HostRequiresReboot
expr:
'(node_reboot_required > 0) * on(instance) group_left (nodename)
node_uname_info{nodename=~".+"}'
for: 4h
labels:
severity: info
annotations:
summary: Host requires reboot (instance {{ $labels.instance }})
description:
"{{ $labels.instance }} requires a reboot.\n VALUE = {{ $value }}\n LABELS = {{
$labels }}"

View File

@@ -4,7 +4,8 @@
I'm running two Kubernetes clusters, one for production and one for testing.
I prefer to use [k3s] as the Kubernetes distribution, because it's lightweight, easy to install, and full featured(see [what-have-k3s-removed-from-upstream-kubernetes] for details).
I prefer to use [k3s] as the Kubernetes distribution, because it's lightweight, easy to install, and
full featured(see [what-have-k3s-removed-from-upstream-kubernetes] for details).
## Hosts
@@ -14,10 +15,10 @@ I prefer to use [k3s] as the Kubernetes distribution, because it's lightweight,
1. `k3s-prod-1-master-1`
1. `k3s-prod-1-master-2`
1. `k3s-prod-1-master-3`
2. `k3s-prod-1-worker-1`
2. `k3s-prod-1-worker-2`
2. `k3s-prod-1-worker-3`
1. For testing:.
1. `k3s-prod-1-worker-1`
1. `k3s-prod-1-worker-2`
1. `k3s-prod-1-worker-3`
1. For testing:.
1. `k3s-test-1-master-1`
2. `k3s-test-1-worker-1`
3. `k3s-test-1-worker-2`
@@ -25,7 +26,9 @@ I prefer to use [k3s] as the Kubernetes distribution, because it's lightweight,
## Kubernetes Resources
Kubernetes resouces are deployed and managed separately through [nix-config/pulumi/k8s/](../../pulumi/k8s/).
Kubernetes resources are deployed and managed separately through
[nix-config/pulumi/k8s/](../../pulumi/k8s/).
[k3s]: https://github.com/k3s-io/k3s/
[what-have-k3s-removed-from-upstream-kubernetes]: https://github.com/k3s-io/k3s/?tab=readme-ov-file#what-have-you-removed-from-upstream-kubernetes
[what-have-k3s-removed-from-upstream-kubernetes]:
https://github.com/k3s-io/k3s/?tab=readme-ov-file#what-have-you-removed-from-upstream-kubernetes

View File

@@ -29,5 +29,3 @@ K3S_TOKEN_FILE=./kubevirt-k3s-token
USB_PATH=/run/media/ryan/NIXOS_K3S
cp $K3S_TOKEN_FILE $USB_PATH
```

View File

@@ -1,9 +1,13 @@
# Library
Some helper functions, used by `flake.nix` to reduce code duplication and make it easier to add new machines:
Some helper functions, used by `flake.nix` to reduce code duplication and make it easier to add new
machines:
1. `attrs.nix`: A set of functions to manupulate attribute sets.
1. `macosSystem.nix`: A function to generate config(attribute set) for macOS([nix-darwin](https://github.com/LnL7/nix-darwin)).
1. `attrs.nix`: A set of functions to manipulate attribute sets.
1. `macosSystem.nix`: A function to generate config(attribute set) for
macOS([nix-darwin](https://github.com/LnL7/nix-darwin)).
1. `nixosSystem.nix`: A function to generate config(attribute set) for NixOS.
1. `colmenaSystem.nix`: A function that generate config(another function) for remote deployment using [colmena](https://github.com/zhaofengli/colmena).
1. `default.nix`: import all the above functions, and some custom useful functions, and export them as a single attribute set.
1. `colmenaSystem.nix`: A function that generate config(another function) for remote deployment
using [colmena](https://github.com/zhaofengli/colmena).
1. `default.nix`: import all the above functions, and some custom useful functions, and export them
as a single attribute set.

View File

@@ -3,4 +3,3 @@
1. `darwin`: macOS-specific configuration.
2. `nixos`: NixOS-specific configuration.
3. `base.nix`: Common configuration for both NixOS and Nix-Darwin.

View File

@@ -2,4 +2,5 @@
This directory contains the modules for [Nix-Darwin](https://github.com/LnL7/nix-darwin).
See [ryan4yin/nix-darwin-kickstarter](https://github.com/ryan4yin/nix-darwin-kickstarter) for a more detailed explanation.
See [ryan4yin/nix-darwin-kickstarter](https://github.com/ryan4yin/nix-darwin-kickstarter) for a more
detailed explanation.

View File

@@ -1,10 +1,13 @@
# Remote Desktop
1. **X11**: We have `xrdp` & `ssh -x` for remote desktop access, which works well for most use cases.
1. **X11**: We have `xrdp` & `ssh -x` for remote desktop access, which works well for most use
cases.
2. **Wayland**: (not tested)
1. `waypipe`: similar to `ssh -X`, transfer wayland data over a ssh connection.
2. [rustdesk](https://github.com/rustdesk/rustdesk): a remote desktop client/server written in rust.
1. confirmed broken currently: <https://www.reddit.com/r/rustdesk/comments/1912373/rustdesk_on_hyprland/>
3. [sunshine server](https://github.com/LizardByte/Sunshine) + [moonlight client](https://github.com/moonlight-stream): It's designed for game streaming, but it can be used for remote desktop as well.
1. broken currently: <https://github.com/LizardByte/Sunshine/pull/1977>
3. `waypipe`: similar to `ssh -X`, transfer wayland data over a ssh connection.
4. [rustdesk](https://github.com/rustdesk/rustdesk): a remote desktop client/server written in rust.
5. confirmed broken currently:
<https://www.reddit.com/r/rustdesk/comments/1912373/rustdesk_on_hyprland/>
6. [sunshine server](https://github.com/LizardByte/Sunshine) +
[moonlight client](https://github.com/moonlight-stream): It's designed for game streaming, but it
can be used for remote desktop as well.
7. broken currently: <https://github.com/LizardByte/Sunshine/pull/1977>

View File

@@ -1,12 +1,16 @@
# Nix Environment Setup for Host: Idols - Ai
> :red_circle: **IMPORTANT**: **Once again, you should NOT deploy this flake directly on your machine! Please write your own configuration from scratch, and use my configuration and documentation for reference only.**
> :red_circle: **IMPORTANT**: **Once again, you should NOT deploy this flake directly on your
> machine! Please write your own configuration from scratch, and use my configuration and
> documentation for reference only.**
This flake prepares a Nix environment for setting my desktop [/hosts/idols_ai](/hosts/idols_ai/)(in main flake) up on a new machine.
This flake prepares a Nix environment for setting my desktop [/hosts/idols_ai](/hosts/idols_ai/)(in
main flake) up on a new machine.
Other docs:
- README for [/hosts/12kingdoms_shoukei](/hosts/12kingdoms_shoukei): [./README.shoukei.md](./README.shoukei.md)
- README for [/hosts/12kingdoms_shoukei](/hosts/12kingdoms_shoukei):
[./README.shoukei.md](./README.shoukei.md)
TODOs:
@@ -14,11 +18,13 @@ TODOs:
## Why an extra flake is needed?
The configuration of the main flake, [/flake.nix](/flake.nix), is heavy, and it takes time to debug & deploy.
This simplified flake is tiny and can be deployed very quickly, it helps me to:
The configuration of the main flake, [/flake.nix](/flake.nix), is heavy, and it takes time to debug
& deploy. This simplified flake is tiny and can be deployed very quickly, it helps me to:
1. Adjust & verify my `hardware-configuration.nix` modification quickly before deploying the main flake.
2. Test some new filesystem related features on a NixOS virtual machine, such as impermanence, Secure Boot, TPM2, Encryption, etc.
1. Adjust & verify my `hardware-configuration.nix` modification quickly before deploying the main
flake.
2. Test some new filesystem related features on a NixOS virtual machine, such as impermanence,
Secure Boot, TPM2, Encryption, etc.
## Steps to Deploying this flake
@@ -34,13 +40,14 @@ First, create a USB install medium from NixOS's official ISO image and boot from
> [Frequently asked questions (FAQ) - cryptsetup](https://gitlab.com/cryptsetup/cryptsetup/wikis/FrequentlyAskedQuestions)
Securing a root file system is where dm-crypt excels, feature and performance-wise.
An encrypted root file system protects everything on the system, it make the system a black box to the attacker.
Securing a root file system is where dm-crypt excels, feature and performance-wise. An encrypted
root file system protects everything on the system, it make the system a black box to the attacker.
1. The EFI system partition(ESP) must be left unencrypted, and is mounted at `/boot`
1. Since the UEFI firmware can only load boot loaders from unencrypted partitions.
1. Since the UEFI firmware can only load boot loaders from unencrypted partitions.
2. Secure Boot is enabled, everything in ESP is signed.
3. The BTRFS file system with subvolumes is used for the root partition, and the swap area is a swapfile on a dedicated BTRFS subvolume, thus the swap area is also encrypted.
3. The BTRFS file system with subvolumes is used for the root partition, and the swap area is a
swapfile on a dedicated BTRFS subvolume, thus the swap area is also encrypted.
And the boot flow is:
@@ -68,7 +75,7 @@ parted /dev/nvme0n1 -- mkpart ESP fat32 2MB 629MB # part-1
parted /dev/nvme0n1 -- set 1 esp on # part-1
# Create the root partition using the rest of the disk
# Format:
# Format:
# mkpart [part-type name fs-type] start end
parted /dev/nvme0n1 -- mkpart primary 630MB 100% # part-1
@@ -80,7 +87,7 @@ Encrypting the root partition:
```bash
lsblk
# show cryptsetup's compiled in defualts
# show cryptsetup's compiled in defaults
cryptsetup --help
# NOTE: `cat shoukei.md | grep luks > luks.sh` to generate this script
@@ -91,7 +98,7 @@ cryptsetup luksFormat --type luks2 --cipher aes-xts-plain64 --hash sha512 --iter
cryptsetup luksDump /dev/nvme0n1p2
# open(unlock) the device with the passphrase you just set
cryptsetup luksOpen /dev/nvme0n1p2 crypted-nixos
cryptsetup luksOpen /dev/nvme0n1p2 encrypted-nixos
# show disk status
lsblk
@@ -103,7 +110,7 @@ Formatting the root partition:
# NOTE: `cat shoukei.md | grep create-btrfs > btrfs.sh` to generate this script
mkfs.fat -F 32 -n ESP /dev/nvme0n1p1 # create-btrfs
# format the root partition with btrfs and label it
mkfs.btrfs -L crypted-nixos /dev/mapper/crypted-nixos # create-btrfs
mkfs.btrfs -L encrypted-nixos /dev/mapper/crypted-nixos # create-btrfs
# mount the root partition and create subvolumes
mount /dev/mapper/crypted-nixos /mnt # create-btrfs
@@ -117,7 +124,7 @@ umount /mnt # create-btrfs
# NOTE: `cat shoukei.md | grep mount-1 > mount-1.sh` to generate this script
# Remount the root partition with the subvolumes you just created
#
#
# Enable zstd compression to:
# 1. Reduce the read/write operations, which helps to:
# 1. Extend the life of the SSD.
@@ -152,10 +159,10 @@ Now, the disk status should be:
```bash
# show disk status
$ lsblk
nvme0n1 259:0 0 1.8T 0 disk
nvme0n1 259:0 0 1.8T 0 disk
├─nvme0n1p1 259:2 0 600M 0 part /mnt/boot
└─nvme0n1p2 259:3 0 1.8T 0 part
└─crypted-nixos 254:0 0 1.8T 0 crypt /mnt/swap
└─nvme0n1p2 259:3 0 1.8T 0 part
└─encrypted-nixos 254:0 0 1.8T 0 crypt /mnt/swap
/mnt/persistent
/mnt/snapshots
/mnt/nix
@@ -243,10 +250,10 @@ reboot
And then reboot.
## Deploying the main flake's NixOS configuration
After rebooting, we need to generate a new SSH key for the new machine, and add it to GitHub, so that the new machine can pull my private secrets repo:
After rebooting, we need to generate a new SSH key for the new machine, and add it to GitHub, so
that the new machine can pull my private secrets repo:
```bash
# 1. Generate a new SSH key with a strong passphrase
@@ -255,8 +262,9 @@ ssh-keygen -t ed25519 -a 256 -C "ryan@idols-ai" -f ~/.ssh/idols_ai
ssh-add ~/.ssh/idols_ai
```
Then follow the instructions in [../secrets/README.md](../secrets/README.md) to rekey all my secrets with the new host's system-level SSH key(`/etc/ssh/ssh_host_ed25519_key`),
so that agenix can decrypt them automatically on the new host when I deploy my NixOS configuration.
Then follow the instructions in [../secrets/README.md](../secrets/README.md) to rekey all my secrets
with the new host's system-level SSH key(`/etc/ssh/ssh_host_ed25519_key`), so that agenix can
decrypt them automatically on the new host when I deploy my NixOS configuration.
After all these steps, we can finally deploy the main flake's NixOS configuration by:
@@ -270,8 +278,10 @@ cd ~/nix-config
just hypr
```
Finally, to enable secure boot, follow the instructions in [lanzaboote - Quick Start](https://github.com/nix-community/lanzaboote/blob/master/docs/QUICK_START.md) and [nix-config/ai/secure-boot.nix](https://github.com/ryan4yin/nix-config/blob/main/hosts/idols_ai/secureboot.nix)
Finally, to enable secure boot, follow the instructions in
[lanzaboote - Quick Start](https://github.com/nix-community/lanzaboote/blob/master/docs/QUICK_START.md)
and
[nix-config/ai/secure-boot.nix](https://github.com/ryan4yin/nix-config/blob/main/hosts/idols_ai/secureboot.nix)
## Change LUKS2's passphrase

View File

@@ -1,16 +1,20 @@
# Nix Environment Setup for Host: 12Kingdoms - Shoukei
> :red_circle: **IMPORTANT**: **Once again, you should NOT deploy this flake directly on your machine! Please write your own configuration from scratch, and use my configuration and documentation for reference only.**
> :red_circle: **IMPORTANT**: **Once again, you should NOT deploy this flake directly on your
> machine! Please write your own configuration from scratch, and use my configuration and
> documentation for reference only.**
> https://wiki.t2linux.org/distributions/nixos/installation/
> https://github.com/NixOS/nixos-hardware/tree/master/apple/t2
This flake prepares a Nix environment for setting my desktop [/hosts/12kingdoms_shoukei](/hosts/12kingdoms_shoukei)(in main flake) up on a new machine.
This flake prepares a Nix environment for setting my desktop
[/hosts/12kingdoms_shoukei](/hosts/12kingdoms_shoukei)(in main flake) up on a new machine.
## Steps to Deploying
First, create a USB install medium from Apple T2's NixOS installer image: https://github.com/t2linux/nixos-t2-iso.git
First, create a USB install medium from Apple T2's NixOS installer image:
https://github.com/t2linux/nixos-t2-iso.git
### 2. Connecting to the Internet
@@ -64,7 +68,7 @@ Now let's recreate the 4th partition via `fdisk`, and then encrypting the root p
```bash
lsblk
# show cryptsetup's compiled in defualts
# show cryptsetup's compiled in defaults
cryptsetup --help
# NOTE: `cat shoukei.md | grep luks > format.sh` to generate this script
@@ -75,7 +79,7 @@ cryptsetup luksFormat --type luks2 --cipher aes-xts-plain64 --hash sha512 --iter
cryptsetup luksDump /dev/nvme0n1p4
# open(unlock) the device with the passphrase you just set
cryptsetup luksOpen /dev/nvme0n1p4 crypted-nixos
cryptsetup luksOpen /dev/nvme0n1p4 encrypted-nixos
# show disk status
lsblk
@@ -86,7 +90,7 @@ Formatting the root partition:
```bash
# NOTE: `cat shoukei.md | egrep "create-btrfs" > create-btrfs.sh` to generate this script
# format the root partition with btrfs and label it
mkfs.btrfs -L crypted-nixos /dev/mapper/crypted-nixos # create-btrfs
mkfs.btrfs -L encrypted-nixos /dev/mapper/crypted-nixos # create-btrfs
# mount the root partition and create subvolumes
mount /dev/mapper/crypted-nixos /mnt # create-btrfs
btrfs subvolume create /mnt/@nix # create-btrfs
@@ -135,7 +139,7 @@ $ lsblk
nvme0n1 259:0 0 1.8T 0 disk
├─nvme0n1p1 259:2 0 600M 0 part /mnt/boot
└─nvme0n1p4 259:3 0 1.8T 0 part
└─crypted-nixos 254:0 0 1.8T 0 crypt /mnt/swap
└─encrypted-nixos 254:0 0 1.8T 0 crypt /mnt/swap
/mnt/persistent
/mnt/snapshots
/mnt/nix
@@ -201,7 +205,7 @@ nixos-enter
mv /etc/machine-id /persistent/etc/
mv /etc/ssh /persistent/etc/
# delte the generated configuration after editing
# delete the generated configuration after editing
rm -f /mnt/etc/nixos
rm ~/nix-config/hosts/idols_ai/hardware-configuration-new.nix
@@ -226,7 +230,8 @@ And then reboot.
## Deploying the main flake's NixOS configuration
After rebooting, we need to generate a new SSH key for the new machine, and add it to GitHub, so that the new machine can pull my private secrets repo:
After rebooting, we need to generate a new SSH key for the new machine, and add it to GitHub, so
that the new machine can pull my private secrets repo:
```bash
# 1. Generate a new SSH key with a strong passphrase
@@ -235,8 +240,9 @@ ssh-keygen -t ed25519 -a 256 -C "ryan@idols-ai" -f ~/.ssh/shoukei
ssh-add ~/.ssh/shoukei
```
Then follow the instructions in [../secrets/README.md](../secrets/README.md) to rekey all my secrets with the new host's system-level SSH key(`/etc/ssh/ssh_host_ed25519_key`),
so that agenix can decrypt them automatically on the new host when I deploy my NixOS configuration.
Then follow the instructions in [../secrets/README.md](../secrets/README.md) to rekey all my secrets
with the new host's system-level SSH key(`/etc/ssh/ssh_host_ed25519_key`), so that agenix can
decrypt them automatically on the new host when I deploy my NixOS configuration.
After all these steps, we can finally deploy the main flake's NixOS configuration by:
@@ -250,4 +256,7 @@ cd ~/nix-config
just s-hypr
```
Finally, to enable secure boot, follow the instructions in [lanzaboote - Quick Start](https://github.com/nix-community/lanzaboote/blob/master/docs/QUICK_START.md) and [nix-config/ai/secure-boot.nix](https://github.com/ryan4yin/nix-config/blob/main/hosts/idols_ai/secureboot.nix)
Finally, to enable secure boot, follow the instructions in
[lanzaboote - Quick Start](https://github.com/nix-community/lanzaboote/blob/master/docs/QUICK_START.md)
and
[nix-config/ai/secure-boot.nix](https://github.com/ryan4yin/nix-config/blob/main/hosts/idols_ai/secureboot.nix)

View File

@@ -7,18 +7,18 @@ There is no need to do this when you have a small number of machines.
But when you have a large number of machines, it is necessary to manage them in a fine-grained way,
otherwise, it will be difficult to manage and maintain them.
The number of my machines has grown to more than 20,
and the increase in scale has shown signs of getting out of control of complexity,
so it is a natural and reasonable choice to use this fine-grained architecture to manage.
The number of my machines has grown to more than 20, and the increase in scale has shown signs of
getting out of control of complexity, so it is a natural and reasonable choice to use this
fine-grained architecture to manage.
## Tests
Testing is not necessary when your configuration is not complex,
but with the increase in the number and configuration of your machines, testing becomes more and more important.
Testing is not necessary when your configuration is not complex, but with the increase in the number
and configuration of your machines, testing becomes more and more important.
We have two types of tests: eval tests and nixos tests,
both of which can help us detect many obscure errors early,
so as to avoid testing directly in the real world, and to avoid failures in personal computers and even corporate online environments.
We have two types of tests: eval tests and nixos tests, both of which can help us detect many
obscure errors early, so as to avoid testing directly in the real world, and to avoid failures in
personal computers and even corporate online environments.
Related projects & docs:
@@ -30,9 +30,9 @@ Related projects & docs:
> TODO: More Tests!
Eval Tests evaluate the expressions and compare the results with the expected results.
It runs fast, but it doesn't build a real machine.
We use eval tests to ensure that some attributes are correctly set for each NixOS host(not Darwin).
Eval Tests evaluate the expressions and compare the results with the expected results. It runs fast,
but it doesn't build a real machine. We use eval tests to ensure that some attributes are correctly
set for each NixOS host(not Darwin).
How to run all the eval tests:
@@ -45,12 +45,15 @@ nix eval .#evalTests --show-trace --print-build-logs --verbose
> WIP: not working yet
NixOS Tests builds and starts virtual machines using our NixOS configuration and run tests on them.
Comparing to eval tests, it runs slow, but it builds a real machine, and we can test the whole system actually works as expected.
Comparing to eval tests, it runs slow, but it builds a real machine, and we can test the whole
system actually works as expected.
Problems:
- [ ] We need a private cache server, so that our NixOS tests do not need to build some custom packages every time we run the tests.
- [ ] Cannot test the whole host, because my host relies on its unique ssh host key to decrypt its agenix secrets.
- [ ] We need a private cache server, so that our NixOS tests do not need to build some custom
packages every time we run the tests.
- [ ] Cannot test the whole host, because my host relies on its unique ssh host key to decrypt its
agenix secrets.
- [ ] Maybe it's better to test every service separately, not the whole host?
How to run NixOS tests for every host:

View File

@@ -104,7 +104,7 @@ in {
settings = {
typos = {
write = true; # Automatically fix typos
ignored-words = [];
configPath = "../.typos.toml";
};
prettier = {
write = true; # Automatically format files

View File

@@ -2,8 +2,10 @@
Overlays for both NixOS and Nix-Darwin.
If you don't know much about overlays, it is recommended to learn the function and usage of overlays through [Overlays - NixOS & Flakes Book](https://nixos-and-flakes.thiscute.world/nixpkgs/overlays).
1. `default.nix`: the entrypoint of overlays, it execute and import all overlay files in the current directory with the given args.
2. `fcitx5`: fcitx5's overlay, add my customized Chinese input method - [小鹤音形输入法](https://flypy.com/)
If you don't know much about overlays, it is recommended to learn the function and usage of overlays
through [Overlays - NixOS & Flakes Book](https://nixos-and-flakes.thiscute.world/nixpkgs/overlays).
1. `default.nix`: the entrypoint of overlays, it execute and import all overlay files in the current
directory with the given args.
2. `fcitx5`: fcitx5's overlay, add my customized Chinese input method -
[小鹤音形输入法](https://flypy.com/)

View File

@@ -4,18 +4,22 @@ Useful for Linux(fcitx5-rime) & macOS(squirrel).
## Linux(fcitx5-rime)
1. pay attention to the `rm -rf .local/share/fcitx5/rime/`, which may contains some auto generated rime config files, which may cause flypy not the default scheme for rime
2. manage `~/.config/fcitx5/profile` in ../home/hyprland/default.nix, which hardcode rime as the default input method, so you do not need to use fcitx-configtool to set rime as the default input method.
3. fcitx5-rime still cannot use on vscode & chrome now... need more time to figure out why and resolve it.
1. pay attention to the `rm -rf .local/share/fcitx5/rime/`, which may contains some auto generated
rime config files, which may cause flypy not the default scheme for rime
2. manage `~/.config/fcitx5/profile` in ../home/hyprland/default.nix, which hardcode rime as the
default input method, so you do not need to use fcitx-configtool to set rime as the default input
method.
3. fcitx5-rime still cannot use on vscode & chrome now... need more time to figure out why and
resolve it.
## macOS(squirrel)
1. pay attention to the `rm -rf ~/Library/Rime/`, which may contains some auto generated rime config files.
1. pay attention to the `rm -rf ~/Library/Rime/`, which may contains some auto generated rime config
files.
## Docs about fcitx5
- [Fcitx5 - Arch Linux Wiki](https://wiki.archlinux.org/title/Fcitx5)
- [Fcitx5 - Official Wiki](https://fcitx-im.org/wiki/Fcitx_5/zh-cn)
- [disscussion about using fcitx5 on hyprland](https://github.com/hyprwm/Hyprland/discussions/421)
- [discussion about using fcitx5 on hyprland](https://github.com/hyprwm/Hyprland/discussions/421)
- [hyprland issue about fcitx5](https://github.com/hyprwm/Hyprland/discussions/421)

View File

@@ -1,41 +1,38 @@
customization:
distribution_code_name: Squirrel
distribution_version: 2019-06-23
rime_version: 1.5.3
patch:
schema_list:
- schema: flypy # 添加小鹤音形
#
# 可用的按键有 Caps_Lock, Shift_L, Shift_R, Control_L, control_R
# Mac 系统上的鼠须管不能区分左、右,因此只有对 Shift_L, Control_L 的设定起作用
#
# 已输入编码时按切换键,可以进一步设定输入法中西文切换的形式
# 可选的临时切换策略有三:
# inline_ascii 在输入法的临时西文编辑区内输入字母、数字、符号、空格等,回车上屏后自动复位到中文
# commit_text 已输入的候选文字上屏并切换至西文输入模式
# commit_code 已输入的编码字符上屏并切换至西文输入模式
# 设为 noop, 屏蔽该切换键
#
# 如果要把Caps Lock 设为只改变字母的大小写而不做中西文切换,可将 Caps_Lock 对应的切换方式设为 noop
# 如果要以Caps Lock 切换到西文模式,默认输出小写字母,请置 ascii_composer/good_old_caps_lock: false
# 如果要以Caps Lock 切换到西文模式,默认输出大写字母,请置 ascii_composer/good_old_caps_lock: true
ascii_composer/good_old_caps_lock: true
ascii_composer/switch_key:
Caps_Lock: noop
Shift_L: commit_code
Shift_R: noop
Control_L: noop
Control_R: noop
key_binder/bindings:
- when: paging
accept: bracketleft
send: Page_Up
- when: has_menu
accept: bracketright
send: Page_Down
customization:
distribution_code_name: Squirrel
distribution_version: 2019-06-23
rime_version: 1.5.3
patch:
schema_list:
- schema: flypy # 添加小鹤音形
#
# 可用的按键有 Caps_Lock, Shift_L, Shift_R, Control_L, control_R
# Mac 系统上的鼠须管不能区分左、右,因此只有对 Shift_L, Control_L 的设定起作用
#
# 已输入编码时按切换键,可以进一步设定输入法中西文切换的形式
# 可选的临时切换策略有三:
# inline_ascii 在输入法的临时西文编辑区内输入字母、数字、符号、空格等,回车上屏后自动复位到中文
# commit_text 已输入的候选文字上屏并切换至西文输入模式
# commit_code 已输入的编码字符上屏并切换至西文输入模式
# 设为 noop, 屏蔽该切换键
#
# 如果要把Caps Lock 设为只改变字母的大小写而不做中西文切换,可将 Caps_Lock 对应的切换方式设为 noop
# 如果要以Caps Lock 切换到西文模式,默认输出小写字母,请置 ascii_composer/good_old_caps_lock: false
# 如果要以Caps Lock 切换到西文模式,默认输出大写字母,请置 ascii_composer/good_old_caps_lock: true
ascii_composer/good_old_caps_lock: true
ascii_composer/switch_key:
Caps_Lock: noop
Shift_L: commit_code
Shift_R: noop
Control_L: noop
Control_R: noop
key_binder/bindings:
- when: paging
accept: bracketleft
send: Page_Up
- when: has_menu
accept: bracketright
send: Page_Down

View File

@@ -24,74 +24,73 @@ menu:
page_size: 5
punctuator:
full_shape: # replace full_shape with half_shape
',' : { commit: }
'.' : { commit: 。 }
'<' : [ 《, 〈, «, ]
'>' : [ 》, 〉, », ]
'/' : { commit: 、 }
'?' : { commit: }
';' : { commit: }
':' : { commit: }
'''' : { pair: [ '', '' ] }
'"' : { pair: [ '“', '”' ] }
'\' : { commit: 、 }
'|' : '|'
'`' : '`'
'~' : { commit: }
'!' : { commit: }
'@' : '@'
'#' : '#'
'%' : { commit: '%' }
'$' : { commit: "$" }
'^' : { commit: …… }
'&' : '&'
'*' : { commit: '*' }
'(' :
')' :
'-' : '-'
'_' : ——
'+' : '+'
'=' : '='
'[' : [ 「, 【, , ]
']' : [ 」, 】, , ]
'{' : [ 『, 〖, ]
'}' : [ 』, 〗, ]
full_shape: # replace full_shape with half_shape
",": { commit: }
".": { commit: 。 }
"<": [《, 〈, «, ]
">": [》, 〉, », ]
"/": { commit: 、 }
"?": { commit: }
";": { commit: }
":": { commit: }
"'": { pair: ["", ""] }
'"': { pair: ["“", "”"] }
'\': { commit: 、 }
"|": "|"
"`": "`"
"~": { commit: }
"!": { commit: }
"@": "@"
"#": "#"
"%": { commit: "%" }
"$": { commit: "$" }
"^": { commit: …… }
"&": "&"
"*": { commit: "*" }
"(":
")":
"-": "-"
"_": ——
"+": "+"
"=": "="
"[": [「, 【, , ]
"]": [」, 】, , ]
"{": [『, 〖, ]
"}": [』, 〗, ]
half_shape:
',' : { commit: }
'.' : { commit: 。 }
'<' : [ 《, 〈, «, ]
'>' : [ 》, 〉, », ]
'/' : { commit: 、 }
'?' : { commit: }
';' : { commit: }
':' : { commit: }
'''' : { pair: [ '', '' ] }
'"' : { pair: [ '“', '”' ] }
'\' : { commit: 、 }
'|' : '|'
'`' : '`'
'~' : { commit: }
'!' : { commit: }
'@' : '@'
'#' : '#'
'%' : { commit: '%' }
'$' : { commit: "$" }
'^' : { commit: …… }
'&' : '&'
'*' : { commit: '*' }
'(' :
')' :
'-' : '-'
'_' : ——
'+' : '+'
'=' : '='
'[' : [ 「, 【, , ]
']' : [ 」, 】, , ]
'{' : [ 『, 〖, ]
'}' : [ 』, 〗, ]
",": { commit: }
".": { commit: 。 }
"<": [《, 〈, «, ]
">": [》, 〉, », ]
"/": { commit: 、 }
"?": { commit: }
";": { commit: }
":": { commit: }
"'": { pair: ["", ""] }
'"': { pair: ["“", "”"] }
'\': { commit: 、 }
"|": "|"
"`": "`"
"~": { commit: }
"!": { commit: }
"@": "@"
"#": "#"
"%": { commit: "%" }
"$": { commit: "$" }
"^": { commit: …… }
"&": "&"
"*": { commit: "*" }
"(":
")":
"-": "-"
"_": ——
"+": "+"
"=": "="
"[": [「, 【, , ]
"]": [」, 】, , ]
"{": [『, 〖, ]
"}": [』, 〗, ]
key_binder:
bindings:

View File

@@ -16,14 +16,14 @@ punctuator:
switches:
- name: ascii_mode
reset: 0
# states: [ 中文, 英文 ]
# states: [ 中文, 英文 ]
- name: full_shape
# states: [ 半角, 全角 ]
# states: [ 半角, 全角 ]
- name: simplification
# states: [ 简, 繁 ]
# states: [ 简, 繁 ]
reset: 0
- name: ascii_punct
# states: [ 。,, ]
# states: [ 。,, ]
reset: 0
engine:
@@ -61,11 +61,11 @@ engine:
speller:
alphabet: "abcdefghijklmnopqrstuvwxyz;'"
initials: ';abcdefghijklmnopqrstuvwxyz'
initials: ";abcdefghijklmnopqrstuvwxyz"
finals: "'"
#delimiter: " '"
max_code_length: 4
auto_select: true #顶字上屏
auto_select: true #顶字上屏
auto_select_pattern: ^;.$|^\w{4}$
auto_clear: max_length #manual|auto|max_length 空码按下一键确认清屏|空码自动清|达到最长码时后码顶上清屏
@@ -77,13 +77,12 @@ translator:
enable_user_dict: false
disable_user_dict_for_patterns:
- "^z.*$"
history:
input: ;f
size: 1 #重复前几次上屏
initial_quality: 1 #首选
input: ;f
size: 1 #重复前几次上屏
initial_quality: 1 #首选
simplification:
opencc_config: s2tw.json
option_name: simplification
@@ -96,7 +95,7 @@ custom_phraseVD:
enable_sentence: false
enable_completion: false
initial_quality: 0 #用户词和系统词重码 置顶
custom_phraseXT:
dictionary: ""
user_dict: flypy_sys
@@ -112,7 +111,7 @@ custom_phraseYH:
enable_sentence: false
enable_completion: false
initial_quality: -1 #用户词和系统词重码居后
custom_phraseQMZ:
dictionary: ""
user_dict: flypy_full
@@ -124,27 +123,26 @@ custom_phraseQMZ:
reverse_lookup:
dictionary: flypydz
comment_format:
# - xform/^//
# - xform/$//
# - xform/^//
# - xform/$//
- xform/ / /
key_binder:
import_preset: default #方案切换相关
bindings:
- {accept: bracketleft, send: Page_Up, when: paging} # [上翻页
- {accept: bracketright, send: Page_Down, when: has_menu} # ]下翻页
- {accept: comma, send: comma, when: paging} #注销逗号翻页
- {accept: period, send: period, when: has_menu} #注销句号翻页
- {accept: semicolon, send: 2, when: has_menu} #分号次选
# - {accept: Release+semicolon, send: semicolon, when: has_menu} #如启用此行,则分号引导符号功能无效
- {accept: Release+period, send: period, when: composing} #句号顶屏
- {accept: Release+comma, send: comma, when: composing} #逗号顶屏
- {accept: "Tab", send: Escape, when: composing}
- {accept: "Shift_R", send: Escape, when: composing}
- {accept: "Shift+space", toggle: full_shape, when: always} #切换全半角
- {accept: "Control+period", toggle: ascii_punct, when: always} #切换中英标点
- {accept: "Control+j", toggle: simplification, when: always} #切换简繁
- { accept: bracketleft, send: Page_Up, when: paging } # [上翻页
- { accept: bracketright, send: Page_Down, when: has_menu } # ]下翻页
- { accept: comma, send: comma, when: paging } #注销逗号翻页
- { accept: period, send: period, when: has_menu } #注销句号翻页
- { accept: semicolon, send: 2, when: has_menu } #分号次选
# - {accept: Release+semicolon, send: semicolon, when: has_menu} #如启用此行,则分号引导符号功能无效
- { accept: Release+period, send: period, when: composing } #句号顶屏
- { accept: Release+comma, send: comma, when: composing } #逗号顶屏
- { accept: "Tab", send: Escape, when: composing }
- { accept: "Shift_R", send: Escape, when: composing }
- { accept: "Shift+space", toggle: full_shape, when: always } #切换全半角
- { accept: "Control+period", toggle: ascii_punct, when: always } #切换中英标点
- { accept: "Control+j", toggle: simplification, when: always } #切换简繁
recognizer:
import_preset: default
@@ -157,7 +155,6 @@ recognizer:
menu:
page_size: 5 #候选项数
style:
horizontal: true #竖排为false

View File

@@ -1,39 +1,38 @@
customization:
distribution_code_name: squirrel
distribution_version: 0.14.0
generator: "squirrel::UIStyleSettings"
modified_time: "2019-06-23"
rime_version: 1.5.3
patch:
"preset_color_schemes/metro":
author: "flypy.com"
back_color: 0xffffff # 候选条背景色
border_color_width: 1
#border_color: 0xe89f00 # 边框色
#preedit_back_color: 0xf0403516 #新增,未知其意
border_height: 8 # 窗口边界高度,大于圆角半径才生效
border_width: 8 # 窗口边界宽度,大于圆角半径才生效
candidate_format: "%c\u2005%@\u2005" # 用 1/6 em 空格 U+2005 来控制编号 %c 和候选词 %@ 前后的空间。
corner_radius: 6 # 窗口圆角半径
#hilited_corner_radius: 6 # 高亮圆角
hilited_text_color: 0x000000 # 编码高亮
hilited_back_color: 0xffffff # 编码背景高亮
hilited_candidate_label_color: 0xeeeeee # 首选编号色
hilited_candidate_text_color: 0xffffff # 首选文字色
hilited_candidate_back_color: 0xe89f00 # 首选背景色
hilited_comment_text_color: 0xcccccc # 首选提示字母色
label_color: 0x555555 # 次选编号色
candidate_text_color: 0x000000 # 次选文字色
candidate_back_color: 0xffffff # 次选背景色
comment_text_color: 0x555555 # 次选提示字母色
horizontal: true # 候选窗横向显示
font_point: 18 # 候选窗文字字号
label_font_point: 14 # 候选窗编号字号
inline_preedit: true # 开启嵌入编码
name: "metro"
text_color: 0x333333 # 编码行文字颜色24位色值16进制BGR顺序
"style/line_spacing": 12 # 候选词的行间距
"style/color_scheme": metro
"style/display_tray_icon": false
"style/text_orientation": horizontal # horizontal | vertical
customization:
distribution_code_name: squirrel
distribution_version: 0.14.0
generator: "squirrel::UIStyleSettings"
modified_time: "2019-06-23"
rime_version: 1.5.3
patch:
"preset_color_schemes/metro":
author: "flypy.com"
back_color: 0xffffff # 候选条背景色
border_color_width: 1
#border_color: 0xe89f00 # 边框色
#preedit_back_color: 0xf0403516 #新增,未知其意
border_height: 8 # 窗口边界高度,大于圆角半径才生效
border_width: 8 # 窗口边界宽度,大于圆角半径才生效
candidate_format: "%c\u2005%@\u2005" # 用 1/6 em 空格 U+2005 来控制编号 %c 和候选词 %@ 前后的空间。
corner_radius: 6 # 窗口圆角半径
#hilited_corner_radius: 6 # 高亮圆角
hilited_text_color: 0x000000 # 编码高亮
hilited_back_color: 0xffffff # 编码背景高亮
hilited_candidate_label_color: 0xeeeeee # 首选编号色
hilited_candidate_text_color: 0xffffff # 首选文字色
hilited_candidate_back_color: 0xe89f00 # 首选背景色
hilited_comment_text_color: 0xcccccc # 首选提示字母色
label_color: 0x555555 # 次选编号色
candidate_text_color: 0x000000 # 次选文字色
candidate_back_color: 0xffffff # 次选背景色
comment_text_color: 0x555555 # 次选提示字母色
horizontal: true # 候选窗横向显示
font_point: 18 # 候选窗文字字号
label_font_point: 14 # 候选窗编号字号
inline_preedit: true # 开启嵌入编码
name: "metro"
text_color: 0x333333 # 编码行文字颜色24位色值16进制BGR顺序
"style/line_spacing": 12 # 候选词的行间距
"style/color_scheme": metro
"style/display_tray_icon": false
"style/text_orientation": horizontal # horizontal | vertical

View File

@@ -1,12 +1,12 @@
# Squirrel settings
# encoding: utf-8
config_version: '0.37'
config_version: "0.37"
us_keyboard_layout: true
# for veteran chord-typist
chord_duration: 0.1 # seconds
chord_duration: 0.1 # seconds
# options: always | never | appropriate
show_notifications_when: appropriate
@@ -22,7 +22,7 @@ style:
# NOTE: do not set a default value for `candidate_list_layout`, in order to
# keep the deprecated `horizontal` option working for existing users.
#candidate_list_layout: stacked # stacked | linear
text_orientation: horizontal # horizontal | vertical
text_orientation: horizontal # horizontal | vertical
inline_preedit: true
corner_radius: 10
@@ -38,7 +38,7 @@ style:
# adjust the base line of vertical text
#base_offset: 6
font_face: 'Lucida Grande'
font_face: "Lucida Grande"
font_point: 21
#label_font_face: 'Lucida Grande'
label_font_point: 18
@@ -117,7 +117,7 @@ preset_color_schemes:
hilited_text_color: 0xffcf9a
hilited_back_color: 0x222222
hilited_candidate_text_color: 0x92f6da
hilited_candidate_back_color: 0x10000000 # 0x333333
hilited_candidate_back_color: 0x10000000 # 0x333333
comment_text_color: 0x606cff
psionics:
@@ -203,7 +203,7 @@ preset_color_schemes:
name: 简约白Clean White
author: Chongyu Zhu <lembacon@gmail.com>, based on 搜狗「简约白」
horizontal: true
candidate_format: '%c %@'
candidate_format: "%c %@"
corner_radius: 6
border_height: 6
border_width: 6
@@ -222,72 +222,72 @@ preset_color_schemes:
apathy:
name: 冷漠Apathy
author: LIANG Hai
horizontal: true # 水平排列
horizontal: true # 水平排列
inline_preedit: true #单行显示false双行显示
candidate_format: "%c\u2005%@\u2005" # 编号 %c 和候选词 %@ 前后的空间
corner_radius: 5 #候选条圆角
candidate_format: "%c\u2005%@\u2005" # 编号 %c 和候选词 %@ 前后的空间
corner_radius: 5 #候选条圆角
border_height: 0
border_width: 0
back_color: 0xFFFFFF #候选条背景色
font_face: "PingFangSC-Regular,HanaMinB" #候选词字体
font_point: 16 #候选字词大小
text_color: 0x424242 #高亮选中词颜色
label_font_face: "STHeitiSC-Light" #候选词编号字体
label_font_point: 12 #候选编号大小
hilited_candidate_text_color: 0xEE6E00 #候选文字颜色
hilited_candidate_back_color: 0xFFF0E4 #候选文字背景色
comment_text_color: 0x999999 #拼音等提示文字颜色
back_color: 0xFFFFFF #候选条背景色
font_face: "PingFangSC-Regular,HanaMinB" #候选词字体
font_point: 16 #候选字词大小
text_color: 0x424242 #高亮选中词颜色
label_font_face: "STHeitiSC-Light" #候选词编号字体
label_font_point: 12 #候选编号大小
hilited_candidate_text_color: 0xEE6E00 #候选文字颜色
hilited_candidate_back_color: 0xFFF0E4 #候选文字背景色
comment_text_color: 0x999999 #拼音等提示文字颜色
dust:
name: 浮尘Dust
author: Superoutman <asticosmo@gmail.com>
horizontal: true # 水平排列
horizontal: true # 水平排列
inline_preedit: true #单行显示false双行显示
candidate_format: "%c\u2005%@\u2005" # 用 1/6 em 空格 U+2005 来控制编号 %c 和候选词 %@ 前后的空间。
corner_radius: 2 #候选条圆角
border_height: 3 # 窗口边界高度,大于圆角半径才生效
border_width: 8 # 窗口边界宽度,大于圆角半径才生效
back_color: 0xeeffffff #候选条背景色
border_color: 0xE0B693 # 边框色
font_face: "HYQiHei-55S Book,HanaMinA Regular" #候选词字体
font_point: 14 #候选字词大小
label_font_face: "SimHei" #候选词编号字体
label_font_point: 10 #候选编号大小
label_color: 0xcbcbcb # 预选栏编号颜色
candidate_text_color: 0x555555 # 预选项文字颜色
text_color: 0x424242 # 拼音行文字颜色24位色值16进制BGR顺序
comment_text_color: 0x999999 # 拼音等提示文字颜色
hilited_text_color: 0x9e9e9e # 高亮拼音 (需要开启内嵌编码)
hilited_candidate_text_color: 0x000000 # 第一候选项文字颜色
hilited_candidate_back_color: 0xfff0e4 # 第一候选项背景背景色
hilited_candidate_label_color: 0x555555 # 第一候选项编号颜色
hilited_comment_text_color: 0x9e9e9e # 注解文字高亮
candidate_format: "%c\u2005%@\u2005" # 用 1/6 em 空格 U+2005 来控制编号 %c 和候选词 %@ 前后的空间。
corner_radius: 2 #候选条圆角
border_height: 3 # 窗口边界高度,大于圆角半径才生效
border_width: 8 # 窗口边界宽度,大于圆角半径才生效
back_color: 0xeeffffff #候选条背景色
border_color: 0xE0B693 # 边框色
font_face: "HYQiHei-55S Book,HanaMinA Regular" #候选词字体
font_point: 14 #候选字词大小
label_font_face: "SimHei" #候选词编号字体
label_font_point: 10 #候选编号大小
label_color: 0xcbcbcb # 预选栏编号颜色
candidate_text_color: 0x555555 # 预选项文字颜色
text_color: 0x424242 # 拼音行文字颜色24位色值16进制BGR顺序
comment_text_color: 0x999999 # 拼音等提示文字颜色
hilited_text_color: 0x9e9e9e # 高亮拼音 (需要开启内嵌编码)
hilited_candidate_text_color: 0x000000 # 第一候选项文字颜色
hilited_candidate_back_color: 0xfff0e4 # 第一候选项背景背景色
hilited_candidate_label_color: 0x555555 # 第一候选项编号颜色
hilited_comment_text_color: 0x9e9e9e # 注解文字高亮
mojave_dark:
name: 沙漠夜Mojave Dark
author: xiehuc <xiehuc@gmail.com>
horizontal: true # 水平排列
inline_preedit: true # 单行显示false双行显示
candidate_format: "%c\u2005%@" # 用 1/6 em 空格 U+2005 来控制编号 %c 和候选词 %@ 前后的空间。
corner_radius: 5 # 候选条圆角
hilited_corner_radius: 3 # 高亮圆角
border_height: 6 # 窗口边界高度,大于圆角半径才生效
border_width: 6 # 窗口边界宽度,大于圆角半径才生效
font_face: "PingFangSC" # 候选词字体
font_point: 16 # 候选字词大小
label_font_point: 14 # 候选编号大小
horizontal: true # 水平排列
inline_preedit: true # 单行显示false双行显示
candidate_format: "%c\u2005%@" # 用 1/6 em 空格 U+2005 来控制编号 %c 和候选词 %@ 前后的空间。
corner_radius: 5 # 候选条圆角
hilited_corner_radius: 3 # 高亮圆角
border_height: 6 # 窗口边界高度,大于圆角半径才生效
border_width: 6 # 窗口边界宽度,大于圆角半径才生效
font_face: "PingFangSC" # 候选词字体
font_point: 16 # 候选字词大小
label_font_point: 14 # 候选编号大小
text_color: 0xdedddd # 拼音行文字颜色24位色值16进制BGR顺序
back_color: 0x252320 # 候选条背景色
label_color: 0x888785 # 预选栏编号颜色
border_color: 0x020202 # 边框色
candidate_text_color: 0xdedddd # 预选项文字颜色
hilited_text_color: 0xdedddd # 高亮拼音 (需要开启内嵌编码)
hilited_back_color: 0x252320 # 高亮拼音 (需要开启内嵌编码)
hilited_candidate_text_color: 0xffffff # 第一候选项文字颜色
hilited_candidate_back_color: 0xcb5d00 # 第一候选项背景背景色
text_color: 0xdedddd # 拼音行文字颜色24位色值16进制BGR顺序
back_color: 0x252320 # 候选条背景色
label_color: 0x888785 # 预选栏编号颜色
border_color: 0x020202 # 边框色
candidate_text_color: 0xdedddd # 预选项文字颜色
hilited_text_color: 0xdedddd # 高亮拼音 (需要开启内嵌编码)
hilited_back_color: 0x252320 # 高亮拼音 (需要开启内嵌编码)
hilited_candidate_text_color: 0xffffff # 第一候选项文字颜色
hilited_candidate_back_color: 0xcb5d00 # 第一候选项背景背景色
hilited_candidate_label_color: 0xffffff # 第一候选项编号颜色
comment_text_color: 0xdedddd # 拼音等提示文字颜色
comment_text_color: 0xdedddd # 拼音等提示文字颜色
#hilited_comment_text_color: 0xdedddd # 注解文字高亮
solarized_light:
@@ -342,9 +342,9 @@ app_options:
ascii_mode: true
no_inline: true
org.vim.MacVim:
ascii_mode: true # 初始爲西文模式
no_inline: true # 不使用行內編輯
vim_mode: true # 退出VIM插入模式自動切換輸入法狀態
ascii_mode: true # 初始爲西文模式
no_inline: true # 不使用行內編輯
vim_mode: true # 退出VIM插入模式自動切換輸入法狀態
com.apple.dt.Xcode:
ascii_mode: true
com.barebones.textwrangler:
@@ -369,4 +369,4 @@ app_options:
inline: true
ru.keepcoder.Telegram:
# 規避 https://github.com/rime/squirrel/issues/475
inline: true
inline: true

View File

@@ -1,24 +1,31 @@
# Secrets Management
> For Website/App's passwords, see [/home/base/desktop/password-store](/home/base/desktop/password-store/README.md) for more details.
> For Website/App's passwords, see
> [/home/base/desktop/password-store](/home/base/desktop/password-store/README.md) for more details.
All my secrets are safely encrypted via agenix, and stored in a separate private GitHub repository and referenced as a flake input in this flake.
All my secrets are safely encrypted via agenix, and stored in a separate private GitHub repository
and referenced as a flake input in this flake.
The encryption is done by using all my host's public keys(`/etc/ssh/ssh_host_ed25519_key`), so that they can only be decrypted on any of my configured hosts.
The host keys are generated locally on each host by openssh without passphrase, and are only readable by `root`, and will never leave the host.
The encryption is done by using all my host's public keys(`/etc/ssh/ssh_host_ed25519_key`), so that
they can only be decrypted on any of my configured hosts. The host keys are generated locally on
each host by openssh without passphrase, and are only readable by `root`, and will never leave the
host.
In this way, all secrets is still encrypted when transmitted over the network and written to `/nix/store`,
they are decrypted only when they are finally used.
In this way, all secrets is still encrypted when transmitted over the network and written to
`/nix/store`, they are decrypted only when they are finally used.
In addition, we further improve the security of secrets files by storing them in a separate private repository.
In addition, we further improve the security of secrets files by storing them in a separate private
repository.
This directory contains this README.md, and a `nixos.nix`/`darwin.nix` that used to decrypt all my secrets via agenix, and then I can use them in this flake.
This directory contains this README.md, and a `nixos.nix`/`darwin.nix` that used to decrypt all my
secrets via agenix, and then I can use them in this flake.
## Adding or Updating Secrets
> All the operations in this section should be performed in my private repository: `nix-secrets`.
This task is accomplished using the [agenix](https://github.com/ryantm/agenix) CLI tool with the `./secrets.nix` file, so you need to have it installed first:
This task is accomplished using the [agenix](https://github.com/ryantm/agenix) CLI tool with the
`./secrets.nix` file, so you need to have it installed first:
To use agenix temporarily, run:
@@ -29,7 +36,8 @@ nix shell nixpkgs#agenix
Suppose you want to add a new secret file `xxx.age`. Follow these steps:
1. Navigate to your private `nix-secrets` repository.
2. Edit `secrets.nix` and add a new entry for `xxx.age`, defining the encryption keys and the secret file path, for example:
2. Edit `secrets.nix` and add a new entry for `xxx.age`, defining the encryption keys and the secret
file path, for example:
```nix
# This file is not imported into your NixOS configuration. It is only used for the agenix CLI.
@@ -72,14 +80,15 @@ Alternatively, you can encrypt an existing file to `xxx.age` using the following
cat xxx | sudo agenix -e ./xxx.age -i /etc/ssh/ssh_host_ed25519_key
```
`agenix` will encrypt the file with all the public keys we defined in `secrets.nix`,
so all the users and systems defined in `secrets.nix` can decrypt it with their private keys.
`agenix` will encrypt the file with all the public keys we defined in `secrets.nix`, so all the
users and systems defined in `secrets.nix` can decrypt it with their private keys.
## Deploying Secrets
> All the operations in this section should be performed in this repository.
First, add your own private `nix-secrets` repository and `agenix` as a flake input, and pass them to sub modules via `specialArgs`:
First, add your own private `nix-secrets` repository and `agenix` as a flake input, and pass them to
sub modules via `specialArgs`:
```nix
{
@@ -145,22 +154,25 @@ Then, create `./secrets/default.nix` with the following content:
}
```
From now on, every time you run `nixos-rebuild switch`, it will decrypt the secrets using the private keys defined in `age.identityPaths`.
It will then symlink the secrets to the path defined by the `age.secrets.<name>.path` argument, which defaults to `/etc/secrets`.
From now on, every time you run `nixos-rebuild switch`, it will decrypt the secrets using the
private keys defined in `age.identityPaths`. It will then symlink the secrets to the path defined by
the `age.secrets.<name>.path` argument, which defaults to `/etc/secrets`.
## Adding a new host
1. `cat` the sytem-level public key(`/etc/ssh/ssh_host_ed25519_key.pub`) of the new host, and send it to an old host which has already been configured.
1. `cat` the system-level public key(`/etc/ssh/ssh_host_ed25519_key.pub`) of the new host, and send
it to an old host which has already been configured.
2. On the old host:
1. Add the public key to `secrets.nix`, and rekey all the secrets via `sudo agenix -r -i /etc/ssh/ssh_host_ed25519_key`.
1. Add the public key to `secrets.nix`, and rekey all the secrets via
`sudo agenix -r -i /etc/ssh/ssh_host_ed25519_key`.
2. Commit and push the changes to `nix-secrets`.
3. On the new host:
1. Clone this repo and run `nixos-rebuild switch` to deploy it, all the secrets will be decrypted automatically via the host private key.
1. Clone this repo and run `nixos-rebuild switch` to deploy it, all the secrets will be decrypted
automatically via the host private key.
## Other Replacements
- [ragenix](https://github.com/yaxitech/ragenix): A Rust reimplementation of agenix.
- agenix is mainly written in bash, and it's error message is quite obscure, a little typo may cause some errors no one can understand.
- agenix is mainly written in bash, and it's error message is quite obscure, a little typo may
cause some errors no one can understand.
- with a type-safe language like Rust, we can get a better error message and less bugs.

View File

@@ -35,7 +35,7 @@ in {
server.operation.enable = mkEnableOption "NixOS Secrets for Operation Servers(Backup, Monitoring, etc)";
server.kubernetes.enable = mkEnableOption "NixOS Secrets for Kubernetes";
impermanence.enable = mkEnableOption "Wether use impermanence and ephemeral root file system";
impermanence.enable = mkEnableOption "whether use impermanence and ephemeral root file system";
};
config =

View File

@@ -1,5 +1,3 @@
# Variables
Some common variables that I use in my NixOS configuration.