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
+1 -1
View File
@@ -1,2 +1,2 @@
patreon: ryan4yin patreon: ryan4yin
custom: ['https://buymeacoffee.com/ryan4yin', 'https://afdian.net/a/ryan4yin'] custom: ["https://buymeacoffee.com/ryan4yin", "https://afdian.net/a/ryan4yin"]
+2 -2
View File
@@ -8,7 +8,7 @@ on:
- "scripts/**" - "scripts/**"
- "**.md" - "**.md"
- "**.nu" - "**.nu"
- 'Justfile' - "Justfile"
pull_request: pull_request:
branches: branches:
- main - main
@@ -16,7 +16,7 @@ on:
- "scripts/**" - "scripts/**"
- "**.md" - "**.md"
- "**.nu" - "**.nu"
- 'Justfile' - "Justfile"
jobs: jobs:
checks: checks:
+1 -1
View File
@@ -4,7 +4,7 @@ on:
branches: branches:
- main - main
tags: tags:
- '*' - "*"
jobs: jobs:
mirror: mirror:
+2 -1
View File
@@ -1,5 +1,6 @@
# https://prettier.io/docs/en/options # https://prettier.io/docs/en/options
semi: false semi: false
singleQuote: false singleQuote: false
printWidth: 80 printWidth: 100
proseWrap: always # always change wrapping in markdown text
trailingComma: es5 trailingComma: es5
+12
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
]
+71 -47
View File
@@ -14,52 +14,64 @@
</a> </a>
</p> </p>
> My configuration is becoming more and more complex, and it may be difficult for beginners to read it. > My configuration is becoming more and more complex, and it may be difficult for beginners to read
> 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. > 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: This repository is home to the nix code that builds my systems:
1. NixOS Desktops: NixOS with home-manager, i3, hyprland, agenix, etc. 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. 2. macOS Desktops: nix-darwin with home-manager, share the same home-manager configuration with
3. NixOS Servers: virtual machines running on Proxmox, with various services, such as kubernetes, homepage, prometheus, grafana, etc. 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. See [./hosts](./hosts) for details of each host.
## Why NixOS & Flakes? ## 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 ## Components
| | NixOS(Wayland) | NixOS(Xorg) | | | NixOS(Wayland) | NixOS(Xorg) |
| --------------------------- | :---------------------------------------------------------------------------------------------------------------- | :---------------------------------------------------------------------------------------------------------------- | | --------------------------- | :------------------------------------------------------------------------------------------------------------------ | :------------------------------------------------------------------------------------------------------------------ |
| **Window Manager** | [Hyprland][Hyprland] | [i3][i3] | | **Window Manager** | [Hyprland][Hyprland] | [i3][i3] |
| **Terminal Emulator** | [Zellij][Zellij] + [Kitty][Kitty] | [Zellij][Zellij] + [Kitty][Kitty] | | **Terminal Emulator** | [Zellij][Zellij] + [Kitty][Kitty] | [Zellij][Zellij] + [Kitty][Kitty] |
| **Bar** | [Waybar][Waybar] | [polybar][polybar] | | **Bar** | [Waybar][Waybar] | [polybar][polybar] |
| **Application Launcher** | [anyrun][anyrun] | [rofi][rofi] | | **Application Launcher** | [anyrun][anyrun] | [rofi][rofi] |
| **Notification Daemon** | [Mako][Mako] | [Dunst][Dunst] | | **Notification Daemon** | [Mako][Mako] | [Dunst][Dunst] |
| **Display Manager** | [GDM][GDM] | [GDM][GDM] | | **Display Manager** | [GDM][GDM] | [GDM][GDM] |
| **Color Scheme** | [Catppuccin][Catppuccin] | [Catppuccin][Catppuccin] | | **Color Scheme** | [Catppuccin][Catppuccin] | [Catppuccin][Catppuccin] |
| **network management tool** | [NetworkManager][NetworkManager] | [NetworkManager][NetworkManager] | | **network management tool** | [NetworkManager][NetworkManager] | [NetworkManager][NetworkManager] |
| **Input method framework** | [Fcitx5][Fcitx5] | [Fcitx5][Fcitx5] | | **Input method framework** | [Fcitx5][Fcitx5] | [Fcitx5][Fcitx5] |
| **System resource monitor** | [Btop][Btop] | [Btop][Btop] | | **System resource monitor** | [Btop][Btop] | [Btop][Btop] |
| **File Manager** | [Yazi][Yazi] + [thunar][thunar] | [Yazi][Yazi] + [thunar][thunar] | | **File Manager** | [Yazi][Yazi] + [thunar][thunar] | [Yazi][Yazi] + [thunar][thunar] |
| **Shell** | [Nushell][Nushell] + [Starship][Starship] | [Nushell][Nushell] + [Starship][Starship] | | **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] | | **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] | | **Media Player** | [mpv][mpv] | [mpv][mpv] |
| **Text Editor** | [Neovim][Neovim] + [DoomEmacs][DoomEmacs] | [Neovim][Neovim] + [DoomEmacs][DoomEmacs] | | **Text Editor** | [Neovim][Neovim] + [DoomEmacs][DoomEmacs] | [Neovim][Neovim] + [DoomEmacs][DoomEmacs] |
| **Fonts** | [Nerd fonts][Nerd fonts] | [Nerd fonts][Nerd fonts] | | **Fonts** | [Nerd fonts][Nerd fonts] | [Nerd fonts][Nerd fonts] |
| **Image Viewer** | [imv][imv] | [imv][imv] | | **Image Viewer** | [imv][imv] | [imv][imv] |
| **Screenshot Software** | [flameshot][flameshot] + [grim][grim] | [flameshot][flameshot] | | **Screenshot Software** | [flameshot][flameshot] + [grim][grim] | [flameshot][flameshot] |
| **Screen Recording** | [OBS][OBS] | [OBS][OBS] | | **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 | | **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] | | **Secure Boot** | [lanzaboote][lanzaboote] | [lanzaboote][lanzaboote] |
Wallpapers: https://github.com/ryan4yin/wallpapers Wallpapers: https://github.com/ryan4yin/wallpapers
@@ -73,8 +85,7 @@ Wallpapers: https://github.com/ryan4yin/wallpapers
## I3 + AstroNvim ## I3 + AstroNvim
![](./_img/i3_2023-07-29_1.webp) ![](./_img/i3_2023-07-29_1.webp) ![](./_img/i3_2023-07-29_2.webp)
![](./_img/i3_2023-07-29_2.webp)
## Neovim ## Neovim
@@ -90,14 +101,19 @@ See [./secrets](./secrets) for details.
## How to Deploy this Flake? ## How to Deploy this Flake?
> :red_circle: **IMPORTANT**: **You should NOT deploy this flake directly on your machine :exclamation: It will not succeed.** > :red_circle: **IMPORTANT**: **You should NOT deploy this flake directly on your machine
> 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, > :exclamation: It will not succeed.** This flake contains my hardware configuration(such as
> and requires my private secrets repository [ryan4yin/nix-secrets](https://github.com/ryan4yin/nix-config/tree/main/secrets) to deploy. > [hardware-configuration.nix](hosts/idols-ai/hardware-configuration.nix),
> You may use this repo as a reference to build your own configuration. > [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: 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`. > Need to restart the machine when switching between `wayland` and `xorg`.
@@ -136,7 +152,8 @@ just ha debug
# just fe 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? ## 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 # 1. generate a proxmox vma image file
nom build .#aquamarine # `nom`(nix-output-monitor) can be replaced by the standard command `nix` 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. # 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 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. # 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 ```shell
# 1. add the ssh key to ssh-agent # 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 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 ## References
@@ -179,17 +198,22 @@ Other dotfiles that inspired me:
- [davidtwco/veritas](https://github.com/davidtwco/veritas) - [davidtwco/veritas](https://github.com/davidtwco/veritas)
- [gvolpe/nix-config](https://github.com/gvolpe/nix-config) - [gvolpe/nix-config](https://github.com/gvolpe/nix-config)
- [Ruixi-rebirth/flakes](https://github.com/Ruixi-rebirth/flakes) - [Ruixi-rebirth/flakes](https://github.com/Ruixi-rebirth/flakes)
- [fufexan/dotfiles](https://github.com/fufexan/dotfiles): gtk theme, xdg, git, media, anyrun, etc. - [fufexan/dotfiles](https://github.com/fufexan/dotfiles): gtk theme, xdg, git, media, anyrun,
- [nix-community/srvos](https://github.com/nix-community/srvos): a collection of opinionated and sharable NixOS configurations for servers etc.
- [nix-community/srvos](https://github.com/nix-community/srvos): a collection of opinionated and
sharable NixOS configurations for servers
- Modularized NixOS Configuration - Modularized NixOS Configuration
- [hlissner/dotfiles](https://github.com/hlissner/dotfiles) - [hlissner/dotfiles](https://github.com/hlissner/dotfiles)
- [viperML/dotfiles](https://github.com/viperML/dotfiles) - [viperML/dotfiles](https://github.com/viperML/dotfiles)
- Hyprland(wayland) - Hyprland(wayland)
- [notwidow/hyprland](https://github.com/notwidow/hyprland): This is where I start my hyprland journey. - [notwidow/hyprland](https://github.com/notwidow/hyprland): This is where I start my hyprland
- [HeinzDev/Hyprland-dotfiles](https://github.com/HeinzDev/Hyprland-dotfiles): Refer to the waybar configuration here. journey.
- [HeinzDev/Hyprland-dotfiles](https://github.com/HeinzDev/Hyprland-dotfiles): Refer to the waybar
configuration here.
- [linuxmobile/kaku](https://github.com/linuxmobile/kaku) - [linuxmobile/kaku](https://github.com/linuxmobile/kaku)
- I3 Window Manager - 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) - [denisse-dev/dotfiles](https://github.com/denisse-dev/dotfiles)
- Neovim/AstroNvim - Neovim/AstroNvim
- [maxbrunet/dotfiles](https://github.com/maxbrunet/dotfiles): astronvim with nix flakes. - [maxbrunet/dotfiles](https://github.com/maxbrunet/dotfiles): astronvim with nix flakes.
-1
View File
@@ -3,4 +3,3 @@
1. `base`: The base module that is suitable for both Linux and macOS. 1. `base`: The base module that is suitable for both Linux and macOS.
2. `linux`: Linux-specific configuration. 2. `linux`: Linux-specific configuration.
3. `darwin`: macOS-specific configuration. 3. `darwin`: macOS-specific configuration.
-1
View File
@@ -3,4 +3,3 @@
1. `server`: Configuration which is suitable for both servers and desktops. 1. `server`: Configuration which is suitable for both servers and desktops.
1. `desktop`: Configuration for desktop environments, such as Hyprland, I3, etc. 1. `desktop`: Configuration for desktop environments, such as Hyprland, I3, etc.
1. `core.nix`: Minimal home-manager's config 1. `core.nix`: Minimal home-manager's config
-1
View File
@@ -1,4 +1,3 @@
# Editors # Editors
See [desktop/editors/](../../desktop/editors/) for more details. See [desktop/editors/](../../desktop/editors/) for more details.
+32 -19
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, I used to spend a lot of time on terminal emulators, to make them match my taste, but now I found
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**! 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. Currently, I only use the most basic features of terminal emulators, such as true color, graphics
Other features such as tabs, scrollback buffer, select/search/copy, etc, are all provided by zellij! protocol, etc. Other features such as tabs, scrollback buffer, select/search/copy, etc, are all
provided by zellij!
My current terminal emulators are: My current terminal emulators are:
1. kitty: My main terminal emulator. 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. 2. wezterm: My secondary terminal emulator.
1. its search ability is very basic, and it's not easy to use. 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 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. 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. 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. 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` ## '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 > 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 '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 'xterm-256color': unknown terminal type
``` ```
or or
``` ```
Error opening terminal: xterm-kitty. 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> For nix-darwin, take a look at <https://github.com/LnL7/nix-darwin/wiki/Terminfo-issues>
### Solutions ### 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 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 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 ```bash
# install on ubuntu / debian # install on ubuntu / debian
@@ -70,4 +84,3 @@ sudo apt-get install kitty-terminfo
# or copy from local machine # or copy from local machine
infocmp -a xterm-kitty | ssh myserver tic -x -o \~/.terminfo /dev/stdin infocmp -a xterm-kitty | ssh myserver tic -x -o \~/.terminfo /dev/stdin
``` ```
+26 -13
View File
@@ -6,7 +6,9 @@
> https://langserver.org/ > 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. - motions such as go-to-definition, find-references, hover.
- **code completion** - **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) - syntax highlighting (use Tree-sitter instead)
- code formatting (use a dedicated formatter 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. LSP was originally developed for Microsoft Visual Studio Code and is now an open standard. In the
In the early 2020s LSP quickly became a "norm" for language intelligence tools providers. early 2020s LSP quickly became a "norm" for language intelligence tools providers.
### Tree-sitter ### 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/ > 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: 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. - 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. **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**. The LSP server parses the code much more deeply and it **not only parses a single file but your
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. 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 does understand the code semantically, while Treesitter only cares about correct syntax**.
#### LSP vs Tree-sitter #### 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**. - Tree-sitter: lightweight, fast, but limited knowledge of your code. mainly used for **syntax
- 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**. 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 ### Formatter vs Linter
@@ -56,7 +66,10 @@ Linting is distinct from Formatting because:
1. **formatting** only restructures how code appears. 1. **formatting** only restructures how code appears.
1. `prettier` is a popular formatter. 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.
- [ ]
+21 -12
View File
@@ -10,15 +10,18 @@ And `Zellij` for a smooth and stable terminal experience.
## Tips ## 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. Many useful keys are already provided by vim, check vim/neovim's docs before you install a new
1. After using Emacs/Neovim more skillfully, I strongly recommend that you read the official documentation of Neovim/vim: 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://vimhelp.org/>: The official vim documentation.
1. <https://neovim.io/doc/user/>: Neovim's official user 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. 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. As for Emacs, Use its GUI version & terminal emulator `vterm` for terminal related operations.
1. Two powerful file search & jump tools: 1. Two powerful file search & jump tools:
1. Tree-view plugins are beginner-friendly and intuitive, but they're not very efficient. 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. 1. **Search by the content**: Useful when you're familiar with the code.
## Tutorial ## Tutorial
@@ -27,13 +30,16 @@ Type `:tutor`(`:Tutor` in Neovim) to learn the basics usage of vim/neovim.
## VIM's Cheetsheet ## 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 ### 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 | | Action | Zellij's Shortcut |
| ------------------------- | ----------------- | | ------------------------- | ----------------- |
@@ -76,10 +82,12 @@ I mainly use Zellij for terminal related operations, here is its terminal shortc
Text Objects: 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. - **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 - **section**: text starting with a section header and ending at the start of the next section
useful to find the start of a function in a C/Go/Java/... program. 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 ### Text Manipulation
@@ -99,7 +107,7 @@ Basics:
| Toggle text's case | `~` | | Toggle text's case | `~` |
| Convert to uppercase | `U` (visual mode) | | Convert to uppercase | `U` (visual mode) |
| Convert to lowercase | `u` (visual mode) | | Convert to lowercase | `u` (visual mode) |
| Align the selected conent | `:center`/`:left`/`:right` | | Align the selected content | `:center`/`:left`/`:right` |
Misc: Misc:
@@ -116,7 +124,7 @@ Misc:
| Action | | | Action | |
| ------------------------------------------------------------------------- | -------------- | | ------------------------------------------------------------------------- | -------------- |
| Sort tye selected lines | `:sort` | | Sort the selected lines | `:sort` |
| Join Selection of Lines With Space | `:join` or `J` | | Join Selection of Lines With Space | `:join` or `J` |
| Join without spaces | `:join!` | | Join without spaces | `:join!` |
| Enter Insert mode at the start/end of the line | `I` / `A` | | 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 | `:% s/old/new/g` |
| Replace all the lines with regex | `:% s@\vhttp://(\w+)@https://\1@gc` | | 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. 2. `\1` means the first matched group in the pattern.
### Replace in the specific lines ### Replace in the specific lines
+9 -8
View File
@@ -2,23 +2,24 @@
## S-expression data(Lisp) ## 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. - [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... - [parinfer(par-in-fer)](https://shaunlebron.github.io/parinfer/): morden, simple, elegant and
- to make parinfer works, you should disable sexp & smartparens in any lisp mode. 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: Some plugins:
- Emacs - Emacs
- [parinfer-rusT-mode](https://github.com/justinbarclay/parinfer-rust-mode) - [parinfer-rusT-mode](https://github.com/justinbarclay/parinfer-rust-mode)
- Neovim - Neovim
- [parinfer-rust](https://github.com/eraserhd/parinfer-rust) - [parinfer-rust](https://github.com/eraserhd/parinfer-rust)
- <https://github.com/Olical/conjure> - <https://github.com/Olical/conjure>
- Helix - 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 ## Other Languages
1. treesitter 1. treesitter
1. ... 1. ...
+17 -10
View File
@@ -6,17 +6,19 @@
2. Org Mode 2. Org Mode
3. Lisp Coding 3. Lisp Coding
4. A top-level tutorial for Emacs(Chinese): <https://nyk.ma/tags/emacs/> 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 ## Screenshot
![](/_img/emacs-2024-01-07.webp) ![](/_img/emacs-2024-01-07.webp)
## Usefull Links ## Useful Links
- Framework: <https://github.com/doomemacs/doomemacs> - Framework: <https://github.com/doomemacs/doomemacs>
- key bindings: - 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> - 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> - module index: <https://github.com/doomemacs/doomemacs/blob/master/docs/modules.org>
- LSP Client: <https://github.com/manateelazycat/lsp-bridge> - LSP Client: <https://github.com/manateelazycat/lsp-bridge>
@@ -44,7 +46,7 @@ when in doubt, run `doom sync`!
```bash ```bash
# testing # testing
just emacs-test just emacs-test
jsut emacs-purge just emacs-purge
just emacs-reload just emacs-reload
# clear test data # clear test data
@@ -59,14 +61,16 @@ just emacs-clean
- So vim/neovim is still the best choice for servers. - So vim/neovim is still the best choice for servers.
- Emacs's markdown-mode works not well with tables, see: - Emacs's markdown-mode works not well with tables, see:
- https://github.com/jrblevin/markdown-mode/issues/380 - 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... - I have to learn magit to avoid this issue...
- GitHub's orgmode support is not well, Markdown is better for GitHub. - 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. - Use markdown for repo's README.md, and use orgmode for my personal notes and docs only.
## Cheetsheet ## 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 ### Basics
@@ -98,7 +102,8 @@ Here is the cheetsheet related to my DoomEmacs configs. Please read vim's common
### File Tree ### File Tree
- treemacs: <https://github.com/Alexander-Miller/treemacs/blob/master/src/elisp/treemacs-mode.el> - 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 | | Action | Shortcut |
| ------------------------------------- | --------- | | ------------------------------------- | --------- |
@@ -199,8 +204,9 @@ Magit is a powerful tool that make git operations easy and intuitive.
Shortcuts in magit's pane: Shortcuts in magit's pane:
> When run `git commit` / `git add` / `git push` /... via magit, multiple Arguments can be set. > When run `git commit` / `git add` / `git push` /... via magit, multiple Arguments can be set. 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. > 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 | | Action | Shortcut |
| -------------------------------------------------- | --------------------------------------------- | | -------------------------------------------------- | --------------------------------------------- |
@@ -220,4 +226,5 @@ Shortcuts in magit's pane:
| Fold/Unfold | `TAB` | | Fold/Unfold | `TAB` |
| Show details of the current unit(commit/stage/...) | `<ENTER>` | | 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>
+50 -29
View File
@@ -1,11 +1,14 @@
# Helix Editor # 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. That's why I'm interested in Helix, Helix is similar to Neovim, but it's more opinionated, and it's
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. 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 ## Tutorial
@@ -14,30 +17,48 @@ Use `:tutor` in helix to start the tutorial.
## Differences between Neovim and Helixer ## Differences between Neovim and Helixer
1. Selecting first, then action. 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. 1. Helix: delete 2 word: `2w` then `x`. You can always see what you're selecting before you apply
2. Neovim: delete 2 word: `d`. then `2w`. No visual feedback before you apply the action. the action.
1. Helix - Morden builtin features: LSP, tree-sitter, fuzzy finder, multi cursors, surround and more. 2. Neovim: delete 2 word: `d`. then `2w`. No visual feedback before you apply the action.
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 - Morden builtin features: LSP, tree-sitter, fuzzy finder, multi cursors, surround and
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. more.
1. Neovim contains a lot of VimScript, and lua is too dynamic, it's hard to debug. 1. They're all available in Neovim too, but you need to find and use the right plugins manually,
1. Personally I'm glad to take a look at a Rust codebase, but not a VimScript/Lua codebase. which takes time and effort.
1. Neovim have a very activate plugin ecosystem, and it's easy to find plugins for almost everything. 1. Helix is built in Rust from scratch. The result is a much smaller codebase and a modern set of
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> defaults. No VimScript. No Lua.
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. Neovim contains a lot of VimScript, and lua is too dynamic, it's hard to debug.
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. Personally I'm glad to take a look at a Rust codebase, but not a VimScript/Lua codebase.
1. <https://github.com/helix-editor/helix/issues/1976#issuecomment-1091074719> 1. Neovim have a very activate plugin ecosystem, and it's easy to find plugins for almost
1. <https://github.com/helix-editor/helix/pull/4649> everything.
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 is still new, and it even do have a stable plugin system yet. A PR to add a plugin
1. Helix do not have a tree-view panel, it's recommended to use Yazi/ranger/Broot instead, and open Helix in them. system is still envolving: <https://github.com/helix-editor/helix/pull/8675>
1. a tree-view plugin may be added after the plugin system is stable, but no one knows when it will be. 1. Neovim has integrated terminal, and it's very powerful. It's quite similar to VSCode's integrated
2. and some Helix users stated that they don't need a tree-view plugin, Helix's file picker is useful and good enough. terminal. I use it a lot.
1. It seems Helix lacks a global substitution command, you should run it in another window(via wm or Zellij). 1. Helix doesn't have a integrated terminal yet, as it's complicated to implement. Users are
1. <https://github.com/helix-editor/helix/issues/196> recommended to use tmux/Zellij or Wezterm/Kitty to implement this feature instead.
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. <https://github.com/helix-editor/helix/issues/1976#issuecomment-1091074719>
1. Complexity and Maintenance Costs vs Batteries Included: <https://github.com/helix-editor/helix/discussions/6356> 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. In Neovim I can make the workflow similar to VSCode/JetBrains by using some plugins, but Helix
It's quite different from the workflow I migrated from VSCode/JetBrains before, I'm very interested in it. 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.
+20 -23
View File
@@ -1,14 +1,14 @@
# Neovim Editor # Neovim Editor
My Neovim config based on [AstroNvim](https://github.com/AstroNvim/AstroNvim). My Neovim config based on [AstroNvim](https://github.com/AstroNvim/AstroNvim). For more details,
For more details, visit the [AstroNvim website](https://astronvim.com/). 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 ## Screenshots
![](/_img/astronvim_2023-07-13_00-39.webp) ![](/_img/astronvim_2023-07-13_00-39.webp) ![](/_img/hyprland_2023-07-29_2.webp)
![](/_img/hyprland_2023-07-29_2.webp)
## Configuration Structure ## Configuration Structure
@@ -47,7 +47,8 @@ just nvim-clear
## Cheetsheet ## 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 ### Incremental Selection
@@ -62,15 +63,16 @@ Provided by nvim-treesitter.
### Search and Jump ### 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 | | Action | Shortcut |
| ----------------- | ------------------------------------------------------------------------------------------------------------- | | ----------------- | ------------------------------------------------------------------------------------------------------------ |
| Search | `/`(normal search), `s`(disable all code highlight, only highlight matches) | | 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) | | 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`, (arround 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 ### Commands & Shortcuts
@@ -92,12 +94,8 @@ Provided by [flash.nvim](https://github.com/folke/flash.nvim), it's a intelligen
### Splitting and Buffers ### Splitting and Buffers
| | | Action | Shortcut | | --------------------- | ------------- | | Horizontal Split | `\` | |
| Action | Shortcut | Vertical Split | `\|` | | Close Buffer | `<Space> + c` |
| --------------------- | ------------- |
| Horizontal Split | `\` |
| Vertical Split | `\|` |
| Close Buffer | `<Space> + c` |
### Editing and Formatting ### Editing and Formatting
@@ -129,9 +127,9 @@ Press `<Space> + D` to view available bindings and options.
### Search and Replace Globally ### Search and Replace Globally
| Description | Shortcut | | Description | Shortcut |
| ------------------------------------------------------------ | ---------------------------------------------------------------- | | ------------------------------------------ | -------------- |
| Open spectre.nvim search and replace panel | `<Space> + ss` | | Open spectre.nvim search and replace panel | `<Space> + ss` |
Search and replace via cli(fd + sad + delta): 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 fd "\\.nix$" . | sad '<pattern>' '<replacement>' | delta
``` ```
### Surrounding Characters ### Surrounding Characters
Provided by mini.surround plugin. Provided by mini.surround plugin.
+14 -13
View File
@@ -1,30 +1,31 @@
# Encryption # 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. [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. using a Cloud provider for key management.
## Asymmetric Encryption ## 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], For morden use, age is recommended, as it use [AEAD encryption function -
If you do not want to manage the keys by yourself, Sops is recommended, as it use KMS for key management. 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 ## Symmetric Encryption
Both age & GnuPG provide symmetric encryption, which is useful for encrypting files for a specific user. 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.
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 [age Format v1]: https://age-encryption.org/v1
+114 -58
View File
@@ -1,10 +1,14 @@
# GNU Privacy Guard(GnuPG) # 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: Key functions of GnuPG:
@@ -20,18 +24,21 @@ Main usage scenarios of GnuPG:
3. Manage your ssh key 3. Manage your ssh key
4. Encrypt your data and store it somewhere. 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: Currently I use both age & GnuPG:
1. Age for secrets encryption(ssh key & other secret files), it's simple and easy to use. 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. 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 ## 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> - English version: <https://github.com/nakov/Practical-Cryptography-for-Developers-Book>
- Chinese version: <https://thiscute.world/tags/cryptography/> - Chinese version: <https://thiscute.world/tags/cryptography/>
@@ -50,12 +57,14 @@ Related Docs:
- [Predictable, Passphrase-Derived PGP Keys][Predictable, Passphrase-Derived PGP Keys] - [Predictable, Passphrase-Derived PGP Keys][Predictable, Passphrase-Derived PGP Keys]
- [OpenPGP - The almost perfect key pair][OpenPGP - The almost perfect key pair] - [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. GnuPG's
OpenPGP standard defines [String-to-Key (S2K)](https://datatracker.ietf.org/doc/html/rfc4880#section-3.7) [OpenPGP protocol specific options](https://gnupg.org/documentation/manuals/gnupg/OpenPGP-Options.html#OpenPGP-Options)
algorithm to derive a symmetric key from your passphrase. 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 --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`. 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. I've added them to my Home Manager's `programs.gpg.settings` option.
### 1. PGP Key(Primary Key) generation ### 1. PGP Key(Primary Key) generation
Key management is the core of OpenPGP standard / GnuPG. 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: 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 ```bash
gpg --full-gen-key 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 --full-gen-key
gpg (GnuPG) 2.4.1; Copyright (C) 2023 g10 Code GmbH gpg (GnuPG) 2.4.1; Copyright (C) 2023 g10 Code GmbH
This is free software: you are free to change and redistribute it. 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. GnuPG needs to construct a user ID to identify your key.
Real name: Real name:
Email address: Email address:
Comment: Comment:
You selected this USER-ID: You selected this USER-ID:
"Ryan Yin (For pass For Work ssh only) <ryan4yin@linux.com>" "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: The generated keys are stored in `~/.gnupg` by default, the functions of each file are as follows:
``` bash ```bash
tree ~/.gnupg/ tree ~/.gnupg/
/Users/ryan/.gnupg/ /Users/ryan/.gnupg/
|-- S.gpg-agent # socket file |-- 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 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 ### 3. Sub Key Generation & Best Practice
In PGP, every keys has a **usage flag** to indicate its usage: 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. - `S` means this key can be used to **Sign** data.
- `E` means this key can be used to **Encrypt** 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**. - `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: The **best practice** is:
1. Generate a primary key with strong cryptography arguments(such as ECC + Curve 25519). 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. 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**. 3. **The Primary Key is extremely important**, Backup the primary key to somewhere absolutely
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. safe(such as two encryptd USB drivers, keep them in different places), and then **delete it from
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! your computer immediately**.
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. 4. The sub key is also important, but you can generate a new one and replace it easily. You can
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... 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. 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. > GnuPG will ask you to input your passphrase to unlock your primary key.
``` bash ```bash
gpg --expert --edit-key ryan4yin@linux.com gpg --expert --edit-key ryan4yin@linux.com
gpg (GnuPG) 2.4.1; Copyright (C) 2023 g10 Code GmbH gpg (GnuPG) 2.4.1; Copyright (C) 2023 g10 Code GmbH
This is free software: you are free to change and redistribute it. 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 gpg --list-public-keys
... ...
``` ```
### 4. Backup & Restore ### 4. Backup & Restore
Export Public Keys(Both Primary Key & Sub Keys): 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): 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, > GnuPG will ask you to input your passphrase to unlock your keypair, because GnuPG need to convert
> because GnuPG need to convert the secret key's format from its internal protection format to the one specified by the OpenPGP protocol. > the secret key's format from its internal protection format to the one specified by the OpenPGP
> protocol.
```bash ```bash
# replace the key ID with your own sec key's ID # 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) Hash alg - SHA1(hash 2)
Salt - 8c 78 58 c0 87 83 8c 2c Salt - 8c 78 58 c0 87 83 8c 2c
Count - 65011712(coded count 255) 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 EdDSA x
Encrypted SHA1 hash 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`, As [Predictable, Passphrase-Derived PGP Keys][Predictable, Passphrase-Derived PGP Keys] says, we'll
the exported primary key is protectd by `SHA1` and `AES128`, which is not secure enough! 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 ```bash
# for simplicity, use the same passphrase as your gpg keypair here # 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 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 ```bash
# delete the primary key and all its sub keys # delete the primary key and all its sub keys
@@ -522,7 +560,8 @@ gpg --decrypt <file>
gpg -d <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 ```bash
# Encrypt a file via symmetric encryption(AES256), and output cleartext. # Encrypt a file via symmetric encryption(AES256), and output cleartext.
@@ -538,27 +577,41 @@ gpg -d <file>
### 7. Public Key Exchange & Revocation ### 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 case of many users, it is very difficult to exchange public keys securely and reliably with
In the Web world, There is a **Chain of Trust**** to resolve this problem: 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. - 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. - 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: 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? - 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. - Many PGP novices follow various tutorials to upload various key with personal privacy (such as
- 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. 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. - **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. - 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: Anyway, let's try to revoke a keypair:
@@ -615,7 +668,8 @@ STuJCp+gru6OtbTCu8Y2LugQeDh7UicM7Ak=
-----END PGP PUBLIC KEY BLOCK----- -----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 ```bash
gpg --import gpg-test-revoke.rev gpg --import gpg-test-revoke.rev
@@ -646,7 +700,8 @@ gpg: 9E78E897B6490D6B: skipped: Unusable public key
gpg: README.md: encryption failed: 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 ## 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] - [Predictable, Passphrase-Derived PGP Keys][Predictable, Passphrase-Derived PGP Keys]
- [OpenPGP - The almost perfect key pair][OpenPGP - The almost perfect key pair] - [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/ [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/
+27 -28
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. 3. Update `./default.nix` to use the new GPG sub keys.
4. Check which Key `pass` currently uses: 4. Check which Key `pass` currently uses:
```bash ```bash
cd ~/.local/share/password-store/ cd ~/.local/share/password-store/
# check which key is used by pass # check which key is used by pass
cat .gpg-id cat .gpg-id
# check which key is really used to encrypt the password # check which key is really used to encrypt the password
gpg --list-packets path/to/any/password.gpg 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>
```
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>
```
+28 -20
View File
@@ -1,32 +1,39 @@
# Zellij - A workspace lives in your terminal # Zellij - A workspace lives in your terminal
Zellij is a terminal workspace with batteries included. Zellij is a terminal workspace with batteries included. At its core, it is a terminal multiplexer
At its core, it is a terminal multiplexer (similar to tmux and screen), but this is merely its infrastructure layer. (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. > By contrast, tmux's key design is counterintuitive, there is no prompt system, and the plug-in
> 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. > 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/...), By this way, We will only use the most basic features of the terminal
while most of the functions of terminal are provided by zellij. emulator(kitty/alacritty/wezterm/...), while most of the functions of terminal are provided by
Thus we can easily switch to any terminal emulator without losing any key functions, zellij. Thus we can easily switch to any terminal emulator without losing any key functions, and do
and do not need to take care of the differences between different terminal emulators. 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! > 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. Some features such as search/copy/scrollback in different terminal emulators are implemented in
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. different ways, and has different user experience. For example, Wezterm's default search function is
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! very basic, and it's not easy to use. Kitty's scrollback search/copy is really tricky to use. As for
Zellij overcomes these problems, and provides a unified user experience for all terminal emulators! 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) ## 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: 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. Use zellij locally for daily work, and use a remote zellij via ssh to do some work on the remote
1. To avoid the key conflicts between zellij and the program running in the terminal, such as vim, tmux, etc. server.
1. To avoid the key conflicts between zellij and the program running in the terminal, such as vim,
tmux, etc.
-1
View File
@@ -4,4 +4,3 @@
2. `shell.nix`: shell related. 2. `shell.nix`: shell related.
3. `rime-squirrel.nix`: [rime-squirrel](https://github.com/rime/squirrel)'s configuration. 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. 4. `default.nix`: the entrypoint of darwin's configuration, it import all the submodules above.
+6 -4
View File
@@ -2,7 +2,9 @@
1. `base`: The base module that is suitable for any NixOS environment. 1. `base`: The base module that is suitable for any NixOS environment.
2. `desktop`: Configuration for desktop environments, such as Hyprland, I3, etc. 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. 3. `server.nix`: Configuration which is suitable for both servers and desktops. It import only
1. used by all my nixos servers. `base` as its submodule.
7. `desktop.nix`: the entrypoint of desktop's configuration, it import both `base` and `desktop` as its submodules. 1. used by all my nixos servers.
1. used by all my nixos desktops. 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.
+9 -7
View File
@@ -1,16 +1,18 @@
# Desktop Related # Desktop Related
3. `base`: all common configurations for all desktops. 3. `base`: all common configurations for all desktops.
4. `hyprland`: Hyprland's configuration. 4. `hyprland`: Hyprland's configuration.
5. `i3`: i3's configuration. 5. `i3`: i3's configuration.
## Why install I3/Hyprland in Home Manager instead of a NixOS Module? ## 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. 1. I3 & Hyprland's configuration file is located in `~/.config`, which can be easily managed by Home
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. 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: 3. By install packages as less as possible in NixOS Module, we can:
1. Make the NixOS system more secure and stable. 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. 2. Make this flake more portable to other non-NixOS systems, as home-manager can be installed on
any Linux system.
@@ -2,15 +2,8 @@
"position": "top", "position": "top",
"layer": "top", "layer": "top",
"modules-left": [ "modules-left": ["custom/launcher", "temperature", "backlight", "hyprland/workspaces"],
"custom/launcher", "modules-center": ["custom/playerctl"],
"temperature",
"backlight",
"hyprland/workspaces"
],
"modules-center": [
"custom/playerctl"
],
"modules-right": [ "modules-right": [
"mpd", "mpd",
"pulseaudio", "pulseaudio",
@@ -21,7 +14,7 @@
"clock", "clock",
"idle_inhibitor", "idle_inhibitor",
"custom/powermenu", "custom/powermenu",
"tray" "tray",
], ],
"hyprland/workspaces": { "hyprland/workspaces": {
"format": "{icon}", "format": "{icon}",
@@ -38,8 +31,8 @@
"9": "", "9": "",
"10": "", "10": "",
"focused": "", "focused": "",
"default": "" "default": "",
} },
}, },
"clock": { "clock": {
@@ -48,137 +41,123 @@
"rotate": 0, "rotate": 0,
"tooltip-format": "<big>{:%B %Y}</big>\n<tt><small>{calendar}</small></tt>", "tooltip-format": "<big>{:%B %Y}</big>\n<tt><small>{calendar}</small></tt>",
"format": " {:%H:%M}", "format": " {:%H:%M}",
"format-alt": " {:%a %b %d, %G}" "format-alt": " {:%a %b %d, %G}",
}, },
"cpu": { "cpu": {
"format": "\udb80\udf5b {usage}%", "format": "\udb80\udf5b {usage}%",
"interval": 1, "interval": 1,
"on-click-middle": "kitty btop", "on-click-middle": "kitty btop",
"on-click-right": "kitty btop" "on-click-right": "kitty btop",
}, },
"custom/launcher": { "custom/launcher": {
"format": "\uf313 ", "format": "\uf313 ",
"on-click": "$HOME/.config/hypr/scripts/menu", "on-click": "$HOME/.config/hypr/scripts/menu",
"on-click-middle": "exec default_wall", "on-click-middle": "exec default_wall",
"on-click-right": "exec wallpaper_random", "on-click-right": "exec wallpaper_random",
"tooltip": false "tooltip": false,
}, },
"custom/powermenu": { "custom/powermenu": {
"format": "\uf011", "format": "\uf011",
"on-click": "$HOME/.config/hypr/scripts/wlogout", "on-click": "$HOME/.config/hypr/scripts/wlogout",
"tooltip": false "tooltip": false,
}, },
"idle_inhibitor": { "idle_inhibitor": {
"format": "{icon}", "format": "{icon}",
"format-icons": { "format-icons": {
"activated": "\uf06e", "activated": "\uf06e",
"deactivated": "\uf070" "deactivated": "\uf070",
}, },
"tooltip": false "tooltip": false,
}, },
"memory": { "memory": {
"format": "\udb83\udee0 {percentage}%", "format": "\udb83\udee0 {percentage}%",
"interval": 1, "interval": 1,
"states": { "states": {
"warning": 85 "warning": 85,
} },
}, },
"mpd": { "mpd": {
"interval": 2, "interval": 2,
"unknown-tag": "N/A", "unknown-tag": "N/A",
"format": "{stateIcon} {artist} - {title}", "format": "{stateIcon} {artist} - {title}",
"format-disconnected": " Disconnected", "format-disconnected": " Disconnected",
"format-paused": "{stateIcon} {artist} - {title}", "format-paused": "{stateIcon} {artist} - {title}",
"format-stopped": "Stopped ", "format-stopped": "Stopped ",
"state-icons": { "state-icons": {
"paused": "", "paused": "",
"playing": "" "playing": "",
}, },
"tooltip-format": "MPD (connected)", "tooltip-format": "MPD (connected)",
"tooltip-format-disconnected": "MPD (disconnected)", "tooltip-format-disconnected": "MPD (disconnected)",
// Commands to execute on events // Commands to execute on events
"on-click": "mpc toggle", "on-click": "mpc toggle",
"on-click-middle": "mpc prev", "on-click-middle": "mpc prev",
"on-click-right": "mpc next", "on-click-right": "mpc next",
"on-update": "", "on-update": "",
"on-scroll-up": "mpc seek +00:00:01", "on-scroll-up": "mpc seek +00:00:01",
"on-scroll-down": "mpc seek -00:00:01", "on-scroll-down": "mpc seek -00:00:01",
"smooth-scrolling-threshold": 1 "smooth-scrolling-threshold": 1,
}, },
"custom/playerctl": { "custom/playerctl": {
"format": "{icon} <span>{}</span>", "format": "{icon} <span>{}</span>",
"return-type": "json", "return-type": "json",
"max-length": 55, "max-length": 55,
"exec": "playerctl -a metadata --format '{\"text\": \" {{markup_escape(title)}}\", \"tooltip\": \"{{playerName}} : {{markup_escape(title)}}\", \"alt\": \"{{status}}\", \"class\": \"{{status}}\"}' -F", "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-middle": "playerctl previous",
"on-click": "playerctl play-pause", "on-click": "playerctl play-pause",
"on-click-right": "playerctl next", "on-click-right": "playerctl next",
"format-icons": { "format-icons": {
"Paused": "<span foreground='#6dd9d9'></span>", "Paused": "<span foreground='#6dd9d9'></span>",
"Playing": "<span foreground='#82db97'></span>" "Playing": "<span foreground='#82db97'></span>",
} },
}, },
"network": { "network": {
"interval": 5, "interval": 5,
//"interface": "wlan*", // (Optional) To force the use of this interface, set it for netspeed to work //"interface": "wlan*", // (Optional) To force the use of this interface, set it for netspeed to work
"format-wifi": " {essid}", "format-wifi": " {essid}",
"format-ethernet": " {ipaddr}/{cidr}", "format-ethernet": " {ipaddr}/{cidr}",
"format-linked": " {ifname} (No IP)", "format-linked": " {ifname} (No IP)",
"format-disconnected": "睊 Disconnected", "format-disconnected": "睊 Disconnected",
"format-disabled": "睊 Disabled", "format-disabled": "睊 Disabled",
"format-alt": " {bandwidthUpBytes} |  {bandwidthDownBytes}", "format-alt": " {bandwidthUpBytes} |  {bandwidthDownBytes}",
"tooltip-format": " {ifname} via {gwaddr}", "tooltip-format": " {ifname} via {gwaddr}",
"on-click-middle": "nm-connection-editor", "on-click-middle": "nm-connection-editor",
"on-click-right": "kitty nmtui" "on-click-right": "kitty nmtui",
}, },
"pulseaudio": { "pulseaudio": {
//"format": "{volume}% {icon} {format_source}", //"format": "{volume}% {icon} {format_source}",
"format": "{icon} {volume}%", "format": "{icon} {volume}%",
"format-muted": " Mute", "format-muted": " Mute",
"format-bluetooth": " {volume}% {format_source}", "format-bluetooth": " {volume}% {format_source}",
"format-bluetooth-muted": " Mute", "format-bluetooth-muted": " Mute",
"format-source": " {volume}%", "format-source": " {volume}%",
"format-source-muted": "", "format-source-muted": "",
"format-icons": { "format-icons": {
"headphone": "", "headphone": "",
"hands-free": "", "hands-free": "",
"headset": "", "headset": "",
"phone": "", "phone": "",
"portable": "", "portable": "",
"car": "", "car": "",
"default": [ "default": ["", "", ""],
"", },
"", "scroll-step": 5.0,
"" // Commands to execute on events
] "on-click": "amixer set Master toggle",
}, "on-click-right": "pavucontrol",
"scroll-step": 5.0, "smooth-scrolling-threshold": 1,
// Commands to execute on events
"on-click": "amixer set Master toggle",
"on-click-right": "pavucontrol",
"smooth-scrolling-threshold": 1,
}, },
"temperature": { "temperature": {
"format": "\uf2c9 {temperatureC}\u00b0C", "format": "\uf2c9 {temperatureC}\u00b0C",
"tooltip": false "tooltip": false,
}, },
"backlight": { "backlight": {
"format": "{icon} {percent}%", "format": "{icon} {percent}%",
"format-icons": [ "format-icons": ["", "", "", "", "", "", "", "", ""],
"",
"",
"",
"",
"",
"",
"",
"",
""
]
}, },
"tray": { "tray": {
"icon-size": 15, "icon-size": 15,
"spacing": 5 "spacing": 5,
}, },
"battery": { "battery": {
"bat": "BAT0", "bat": "BAT0",
@@ -186,7 +165,7 @@
"interval": 60, "interval": 60,
"states": { "states": {
"warning": 30, "warning": 30,
"critical": 15 "critical": 15,
}, },
"max-length": 20, "max-length": 20,
"format": "{icon} {capacity}%", "format": "{icon} {capacity}%",
@@ -196,12 +175,6 @@
"format-plugged": " {capacity}%", "format-plugged": " {capacity}%",
"format-alt": "{icon} {time}", "format-alt": "{icon} {time}",
"format-full": " {capacity}%", "format-full": " {capacity}%",
"format-icons": [ "format-icons": [" ", " ", " ", " ", " "],
" ",
" ",
" ",
" ",
" "
]
}, },
} }
@@ -36,5 +36,3 @@
@define-color pink #f5c2e7; @define-color pink #f5c2e7;
@define-color flamingo #f2cdcd; @define-color flamingo #f2cdcd;
@define-color rosewater #f5e0dc; @define-color rosewater #f5e0dc;
@@ -1,52 +1,57 @@
/** ********** Fonts ********** **/ /** ********** Fonts ********** **/
* { * {
font-family: "JetBrains Mono", "Iosevka Nerd Font", sans-serif; font-family: "JetBrains Mono", "Iosevka Nerd Font", sans-serif;
font-size: 14px; font-size: 14px;
font-weight: bold; font-weight: bold;
} }
/** ********** Main Window ********** **/ /** ********** Main Window ********** **/
window { window {
background-color: #1E1E2E; background-color: #1e1e2e;
} }
/** ********** Buttons ********** **/ /** ********** Buttons ********** **/
button { button {
background-color: #242434; background-color: #242434;
color: #FFFFFF; color: #ffffff;
border: 2px solid #282838; border: 2px solid #282838;
border-radius: 20px; border-radius: 20px;
background-repeat: no-repeat; background-repeat: no-repeat;
background-position: center; background-position: center;
background-size: 35%; background-size: 35%;
} }
button:focus, button:active, button:hover { button:focus,
background-color: #89B4FA; button:active,
outline-style: none; button:hover {
background-color: #89b4fa;
outline-style: none;
} }
/** ********** Icons ********** **/ /** ********** Icons ********** **/
#lock { #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 { #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 { #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 { #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 { #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 { #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"));
} }
+2 -1
View File
@@ -1,3 +1,4 @@
# Scripts for I3 Blocks # 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.
+4 -4
View File
@@ -18,7 +18,7 @@ zram0 254:0 0 0B 0 disk
nvme0n1 259:0 0 1.8T 0 disk nvme0n1 259:0 0 1.8T 0 disk
├─nvme0n1p1 259:1 0 630M 0 part /boot ├─nvme0n1p1 259:1 0 630M 0 part /boot
└─nvme0n1p2 259:2 0 1.8T 0 part └─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 /swap
/snapshots /snapshots
/home/ryan/tmp /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 ### 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: Then, run the following commands:
@@ -145,5 +147,3 @@ cd ~/nix-config
# NOTE: the root password you set here will be discarded when reboot # 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 sudo nixos-install --root /mnt --flake .#rakushun --no-root-password --show-trace --verbose
``` ```
+1 -4
View File
@@ -8,12 +8,9 @@ Related:
- <https://github.com/NixOS/nixos-hardware/tree/master/apple/t2> - <https://github.com/NixOS/nixos-hardware/tree/master/apple/t2>
- <https://wiki.t2linux.org/distributions/nixos/installation/> - <https://wiki.t2linux.org/distributions/nixos/installation/>
TODOs: TODOs:
- [ ] Resume from suspend(close the lid) doesn't work - [ ] Resume from suspend(close the lid) doesn't work
- [ ] Show battery percentage in i3blocks/waybar - [ ] Show battery percentage in i3blocks/waybar
- [ ] Touchbar unusable some times - [ ] 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
+5 -6
View File
@@ -2,7 +2,6 @@
LUKS encrypted SSD for NixOS, on Orange Pi 5. LUKS encrypted SSD for NixOS, on Orange Pi 5.
## Showcases ## Showcases
![](../../_img/2024-03-07_orangepi5_suzu.webp) ![](../../_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 nvme0n1 259:0 0 238.5G 0 disk
├─nvme0n1p1 259:1 0 630M 0 part /boot ├─nvme0n1p1 259:1 0 630M 0 part /boot
└─nvme0n1p2 259:2 0 237.9G 0 part └─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 /snapshots
/swap /swap
/home/ryan/tmp /home/ryan/tmp
@@ -97,7 +96,7 @@ Caches (sum of all):
L3: 3 MiB (1 instance) 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 ### 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 ### 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: Then, run the following commands:
@@ -145,5 +146,3 @@ cd ~/nix-config
# NOTE: the root password you set here will be discarded when reboot # 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 sudo nixos-install --root /mnt --flake .#suzu --no-root-password --show-trace --verbose
``` ```
+27 -15
View File
@@ -5,32 +5,42 @@
1. `harmonica`: MacBook Pro 2020 13-inch i5 16G, for personal use. 1. `harmonica`: MacBook Pro 2020 13-inch i5 16G, for personal use.
2. `idols` 2. `idols`
1. `ai`: My main computer, with NixOS + I5-13600KF + RTX 4090 GPU, for gaming & daily use. 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. 2. `aquamarine`: My NixOS virtual machine as a router(IPv4 only) with a transparent proxy to
3. `ruby`: Another NixOS VM running operation and maintenance related services, such as prometheus, grafana, restic, etc. bypass the G|F|W.
4. `kana`: Yet another NixOS VM running some common applications, such as hompage, file browser, torrent downloader, etc. 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: 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. 4. `rolling_girls`: My RISCV64 hosts.
1. `nozomi`: Lichee Pi 4A, TH1520(4xC910@2.0G), 16GB RAM + 32G eMMC + 128G SD Card. 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. 2. `yukina`: Milk-V Mars, JH7110(4xU74@1.5 GHz), 4G RAM + No eMMC + 64G SD Card.
5. `12kingdoms`: 5. `12kingdoms`:
1. `shoukei`: NixOS on Macbook Pro 2020 Intel i5, 13.3-inch, 16G RAM + 512G SSD. 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. `suzu`: Orange Pi 5, RK3588s(4xA76 + 4xA55), GPU(4Cores, Mail-G610), NPU(6Tops@int8), 8G RAM +
1. `rakushun`: Orange Pi 5 Plus, RK3588(4xA76 + 4xA55), GPU(4Cores, Mail-G610), NPU(6Tops@int8), 16G RAM + 2T SSD. 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 6. `k8s`: My Kubernetes Clusters
## How to add a new host ## How to add a new host
1. Under `hosts/` 1. Under `hosts/`
1. Create a new folder under `hosts/` with the name of the new host. 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`. 3. If the new host need to use home-manager, add its custom config into `hosts/<name>/home.nix`.
1. Under `outputs/` 1. Under `outputs/`
1. Add a new nix file named `outputs/<system-architecture>/src/<name>.nix`. 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. 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. 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. 3. [Optional] Add a new unit test file under `outputs/<system-architecture>/tests/<name>.nix` to
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. 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 ## idols - Oshi no Ko
@@ -44,9 +54,13 @@ My All RISCV64 hosts.
## Distributed Building ## 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) ![](/_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): [Oshi no Ko 【推しの子】 - Wikipedia](https://en.wikipedia.org/wiki/Oshi_no_Ko):
![](/_img/idols-famaily.webp) ![](/_img/idols-famaily.webp) ![](/_img/idols-ai.webp)
![](/_img/idols-ai.webp)
[The Rolling Girls【ローリング☆ガールズ】 - Wikipedia](https://en.wikipedia.org/wiki/The_Rolling_Girls): [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) [List of Twelve Kingdoms characters](https://en.wikipedia.org/wiki/List_of_Twelve_Kingdoms_characters)
![](/_img/12kingdoms-1.webp) ![](/_img/12kingdoms-1.webp) ![](/_img/12kingdoms-Youko-Rakushun.webp)
![](/_img/12kingdoms-Youko-Rakushun.webp)
[List of Frieren characters](https://en.wikipedia.org/wiki/List_of_Frieren_characters) [List of Frieren characters](https://en.wikipedia.org/wiki/List_of_Frieren_characters)
+4 -4
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 tmpfs tmpfs 100K 0 100K 0% /var/lib/lxd/devlxd
/dev/mapper/crypted-nixos btrfs 1.9T 630G 1.3T 34% /tmp /dev/mapper/crypted-nixos btrfs 1.9T 630G 1.3T 34% /tmp
~ ~
lsblk lsblk
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS
zram0 253:0 0 15.6G 0 disk [SWAP] 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 ├─nvme0n1p1 259:2 0 598M 0 part /boot
└─nvme0n1p2 259:3 0 1.8T 0 part └─nvme0n1p2 259:3 0 1.8T 0 part
└─crypted-nixos 254:0 0 1.8T 0 crypt /tmp └─encrypted-nixos 254:0 0 1.8T 0 crypt /tmp
/swap/swapfile /swap/swapfile
/swap /swap
/snapshots /snapshots
+17 -11
View File
@@ -1,14 +1,15 @@
# Idols - Aquamarine # 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 ## Troubleshooting
### Can not access the global internet ### 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. - 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`. 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. `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. `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. 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. 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. 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. Server **discovery**: The DHCP client broadcasts a DHCPDISCOVER message on the network
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. subnet using the destination address 255.255.255.255 (limited broadcast) or the specific
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. subnet broadcast address (directed broadcast).
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. 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. 1. So if you see only `DISCOVER` messages, the dhsmasq is not working properly.
## References ## References
- <https://github.com/ghostbuster91/blogposts/blob/main/router2023-part2/main.md> - <https://github.com/ghostbuster91/blogposts/blob/main/router2023-part2/main.md>
- <https://github.com/ghostbuster91/nixos-router> - <https://github.com/ghostbuster91/nixos-router>
+3 -3
View File
@@ -2,8 +2,9 @@
Host running some common applications, such as hompage, file browser, torrent downloader, etc. 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, All the services assumes a reverse proxy to be setup in the front, they are all listening on
and a caddy service is listening on the local network interface and proxy the requests to the services. localhost, and a caddy service is listening on the local network interface and proxy the requests to
the services.
## 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. uptime-kuma: uptime monitoring
1. alist/filebrower: File browser for local/SMB/Cloud 1. alist/filebrower: File browser for local/SMB/Cloud
1. excalidraw/DDTV/owncast/jitsi-meet/... 1. excalidraw/DDTV/owncast/jitsi-meet/...
-1
View File
@@ -1,4 +1,3 @@
# Homepage for my Homelab # Homepage for my Homelab
> WIP, just a demo for now > WIP, just a demo for now
@@ -6,4 +6,3 @@
- Github: - Github:
- abbr: GH - abbr: GH
href: https://github.com/ryan4yin href: https://github.com/ryan4yin
@@ -4,5 +4,3 @@
# read kubbecofig from $KUBECONFIG or $HOME/.kube/config # read kubbecofig from $KUBECONFIG or $HOME/.kube/config
# mode: default # mode: default
mode: disabled mode: disabled
@@ -6,19 +6,19 @@
- PVE-UM560: - PVE-UM560:
icon: si-proxmox icon: si-proxmox
href: https://192.168.5.173:8006/ 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/ siteMonitor: https://192.168.5.173:8006/
- PVE-S500Plus: - PVE-S500Plus:
icon: si-proxmox icon: si-proxmox
href: https://192.168.5.174:8006/ 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/ siteMonitor: https://192.168.5.174:8006/
- PVE-GTR5: - PVE-GTR5:
icon: si-proxmox icon: si-proxmox
href: https://192.168.5.172:8006/ 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/ siteMonitor: https://192.168.5.172:8006/
- Homelab Monitoring: - Homelab Monitoring:
@@ -26,7 +26,7 @@
icon: si-grafana icon: si-grafana
href: http://grafana.writefor.fun href: http://grafana.writefor.fun
description: Data visualised on dashboards description: Data visualised on dashboards
siteMonitor: http://grafana.writefor.fun siteMonitor: http://grafana.writefor.fun
- Prometheus Dashboard: - Prometheus Dashboard:
icon: si-prometheus icon: si-prometheus
href: http://prometheus.writefor.fun href: http://prometheus.writefor.fun
@@ -44,7 +44,6 @@
href: "http://sftpgo.writefor.fun/web/admin/folders" href: "http://sftpgo.writefor.fun/web/admin/folders"
description: WebDAV & SFTP server description: WebDAV & SFTP server
siteMonitor: http://sftpgo.writefor.fun/ siteMonitor: http://sftpgo.writefor.fun/
# - Kubernetes Monitoring: # - Kubernetes Monitoring:
# # TODO: Update this # # TODO: Update this
# - Emby: # - Emby:
@@ -16,9 +16,8 @@ language: zh
# You can then pass provider instead of apiKey in your widget configuration. # You can then pass provider instead of apiKey in your widget configuration.
providers: providers:
# read api keys from environment variables # read api keys from environment variables
openweathermap: {{HOMEPAGE_VAR_WEATHERAPI_APIKEY}} openweathermap: { { HOMEPAGE_VAR_WEATHERAPI_APIKEY } }
weatherapi: {{HOMEPAGE_VAR_WEATHERAPI_APIKEY}} weatherapi: { { HOMEPAGE_VAR_WEATHERAPI_APIKEY } }
background: background:
image: /images/rolling-girls.png image: /images/rolling-girls.png
@@ -29,7 +28,7 @@ background:
theme: dark # or light theme: dark # or light
# Supported colors are: # Supported colors are:
# slate, gray, zinc, neutral, stone, amber, # slate, gray, zinc, neutral, stone, amber,
# yellow, lime, green, emerald, teal, cyan, # yellow, lime, green, emerald, teal, cyan,
# sky, blue, indigo, violet, purple, fuchsia, pink, rose, red, white # sky, blue, indigo, violet, purple, fuchsia, pink, rose, red, white
@@ -46,7 +45,7 @@ layout:
tab: First tab: First
Group A: Group A:
initiallyCollapsed: true # collasped by default initiallyCollapsed: true # collapsed by default
tab: First tab: First
style: row style: row
columns: 4 columns: 4
-1
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. prometheus + alertmanager + grafana + loki: Monitor the metrics/logs of my homelab.
1. restic: Backup my personal data to cloud or NAS. 1. restic: Backup my personal data to cloud or NAS.
1. synthing: Sync file between android/macbook/PC and NAS. 1. synthing: Sync file between android/macbook/PC and NAS.
+1 -1
View File
@@ -2,7 +2,7 @@ apiVersion: 1
providers: providers:
# <string> an unique provider name. Required # <string> an unique provider name. Required
- name: 'Dashboards' - name: "Dashboards"
# <int> Org id. Default to 1 # <int> Org id. Default to 1
orgId: 1 orgId: 1
# <string> provider type. Default to 'file' # <string> provider type. Default to 'file'
@@ -1,4 +1,4 @@
# Grafana Dashbaords # Grafana Dashboards
## Homelab ## Homelab
@@ -8,4 +8,3 @@
## Kubernetes ## Kubernetes
1. https://github.com/dotdc/grafana-dashboards-kubernetes/ 1. https://github.com/dotdc/grafana-dashboards-kubernetes/
@@ -128,11 +128,7 @@
"cacheTimeout": null, "cacheTimeout": null,
"colorBackground": false, "colorBackground": false,
"colorValue": false, "colorValue": false,
"colors": [ "colors": ["#299c46", "rgba(237, 129, 40, 0.89)", "#d44a3a"],
"#299c46",
"rgba(237, 129, 40, 0.89)",
"#d44a3a"
],
"datasource": "$datasource", "datasource": "$datasource",
"decimals": 0, "decimals": 0,
"format": "short", "format": "short",
@@ -297,7 +293,7 @@
"unit": "s" "unit": "s"
}, },
{ {
"alias": "Last reload sucessfull", "alias": "Last reload successful",
"colorMode": "cell", "colorMode": "cell",
"colors": [ "colors": [
"rgba(245, 54, 54, 0.9)", "rgba(245, 54, 54, 0.9)",
@@ -308,10 +304,7 @@
"decimals": 2, "decimals": 2,
"mappingType": 1, "mappingType": 1,
"pattern": "Value #C", "pattern": "Value #C",
"thresholds": [ "thresholds": ["0", "1"],
"0",
"1"
],
"type": "number", "type": "number",
"unit": "short" "unit": "short"
}, },
@@ -363,11 +356,7 @@
"cacheTimeout": null, "cacheTimeout": null,
"colorBackground": false, "colorBackground": false,
"colorValue": false, "colorValue": false,
"colors": [ "colors": ["#299c46", "rgba(237, 129, 40, 0.89)", "#d44a3a"],
"#299c46",
"rgba(237, 129, 40, 0.89)",
"#d44a3a"
],
"datasource": "$datasource", "datasource": "$datasource",
"decimals": 0, "decimals": 0,
"description": "Number of peers in the Alertmanager cluster.", "description": "Number of peers in the Alertmanager cluster.",
@@ -445,11 +434,7 @@
"cacheTimeout": null, "cacheTimeout": null,
"colorBackground": false, "colorBackground": false,
"colorValue": false, "colorValue": false,
"colors": [ "colors": ["#299c46", "rgba(237, 129, 40, 0.89)", "#d44a3a"],
"#299c46",
"rgba(237, 129, 40, 0.89)",
"#d44a3a"
],
"datasource": "$datasource", "datasource": "$datasource",
"description": "Current number of active alerts.", "description": "Current number of active alerts.",
"format": "none", "format": "none",
@@ -526,11 +511,7 @@
"cacheTimeout": null, "cacheTimeout": null,
"colorBackground": false, "colorBackground": false,
"colorValue": false, "colorValue": false,
"colors": [ "colors": ["#299c46", "rgba(237, 129, 40, 0.89)", "#d44a3a"],
"#299c46",
"rgba(237, 129, 40, 0.89)",
"#d44a3a"
],
"datasource": "$datasource", "datasource": "$datasource",
"description": "Current number of suppressed alerts.", "description": "Current number of suppressed alerts.",
"format": "none", "format": "none",
@@ -607,11 +588,7 @@
"cacheTimeout": null, "cacheTimeout": null,
"colorBackground": false, "colorBackground": false,
"colorValue": false, "colorValue": false,
"colors": [ "colors": ["#299c46", "rgba(237, 129, 40, 0.89)", "#d44a3a"],
"#299c46",
"rgba(237, 129, 40, 0.89)",
"#d44a3a"
],
"datasource": "$datasource", "datasource": "$datasource",
"description": "Current number of active silences.", "description": "Current number of active silences.",
"format": "none", "format": "none",
@@ -2469,7 +2446,7 @@
"expr": "increase(alertmanager_cluster_reconnections_total{instance=~\"$instance\"}[$__interval])", "expr": "increase(alertmanager_cluster_reconnections_total{instance=~\"$instance\"}[$__interval])",
"format": "time_series", "format": "time_series",
"intervalFactor": 1, "intervalFactor": 1,
"legendFormat": "Sucessful reconnections", "legendFormat": "Successful reconnections",
"refId": "A" "refId": "A"
}, },
{ {
@@ -2578,7 +2555,7 @@
"expr": "increase(alertmanager_cluster_reconnections_total{instance=~\"$instance\"}[$__interval])", "expr": "increase(alertmanager_cluster_reconnections_total{instance=~\"$instance\"}[$__interval])",
"format": "time_series", "format": "time_series",
"intervalFactor": 1, "intervalFactor": 1,
"legendFormat": "Sucessful reconnections", "legendFormat": "Successful reconnections",
"refId": "A" "refId": "A"
}, },
{ {
@@ -2687,7 +2664,7 @@
"expr": "increase(alertmanager_cluster_reconnections_total{instance=~\"$instance\"}[$__interval])", "expr": "increase(alertmanager_cluster_reconnections_total{instance=~\"$instance\"}[$__interval])",
"format": "time_series", "format": "time_series",
"intervalFactor": 1, "intervalFactor": 1,
"legendFormat": "Sucessful reconnections", "legendFormat": "Successful reconnections",
"refId": "A" "refId": "A"
}, },
{ {
@@ -2796,7 +2773,7 @@
"expr": "increase(alertmanager_cluster_reconnections_total{instance=~\"$instance\"}[$__interval])", "expr": "increase(alertmanager_cluster_reconnections_total{instance=~\"$instance\"}[$__interval])",
"format": "time_series", "format": "time_series",
"intervalFactor": 1, "intervalFactor": 1,
"legendFormat": "Sucessful reconnections", "legendFormat": "Successful reconnections",
"refId": "A" "refId": "A"
}, },
{ {
@@ -10161,15 +10138,11 @@
"format": "time_series", "format": "time_series",
"groupBy": [ "groupBy": [
{ {
"params": [ "params": ["$__interval"],
"$__interval"
],
"type": "time" "type": "time"
}, },
{ {
"params": [ "params": ["null"],
"null"
],
"type": "fill" "type": "fill"
} }
], ],
@@ -10183,9 +10156,7 @@
"select": [ "select": [
[ [
{ {
"params": [ "params": ["value"],
"value"
],
"type": "field" "type": "field"
}, },
{ {
@@ -10305,15 +10276,11 @@
"format": "time_series", "format": "time_series",
"groupBy": [ "groupBy": [
{ {
"params": [ "params": ["$__interval"],
"$__interval"
],
"type": "time" "type": "time"
}, },
{ {
"params": [ "params": ["null"],
"null"
],
"type": "fill" "type": "fill"
} }
], ],
@@ -10327,9 +10294,7 @@
"select": [ "select": [
[ [
{ {
"params": [ "params": ["value"],
"value"
],
"type": "field" "type": "field"
}, },
{ {
@@ -10449,15 +10414,11 @@
"format": "time_series", "format": "time_series",
"groupBy": [ "groupBy": [
{ {
"params": [ "params": ["$__interval"],
"$__interval"
],
"type": "time" "type": "time"
}, },
{ {
"params": [ "params": ["null"],
"null"
],
"type": "fill" "type": "fill"
} }
], ],
@@ -10471,9 +10432,7 @@
"select": [ "select": [
[ [
{ {
"params": [ "params": ["value"],
"value"
],
"type": "field" "type": "field"
}, },
{ {
@@ -10593,15 +10552,11 @@
"format": "time_series", "format": "time_series",
"groupBy": [ "groupBy": [
{ {
"params": [ "params": ["$__interval"],
"$__interval"
],
"type": "time" "type": "time"
}, },
{ {
"params": [ "params": ["null"],
"null"
],
"type": "fill" "type": "fill"
} }
], ],
@@ -10615,9 +10570,7 @@
"select": [ "select": [
[ [
{ {
"params": [ "params": ["value"],
"value"
],
"type": "field" "type": "field"
}, },
{ {
@@ -11131,11 +11084,7 @@
"refresh": "5m", "refresh": "5m",
"schemaVersion": 18, "schemaVersion": 18,
"style": "dark", "style": "dark",
"tags": [ "tags": ["alertmanager", "prometheus", "alerting"],
"alertmanager",
"prometheus",
"alerting"
],
"templating": { "templating": {
"list": [ "list": [
{ {
@@ -11185,32 +11134,11 @@
"to": "now" "to": "now"
}, },
"timepicker": { "timepicker": {
"refresh_intervals": [ "refresh_intervals": ["5s", "10s", "30s", "1m", "5m", "15m", "30m", "1h", "2h", "1d"],
"5s", "time_options": ["5m", "15m", "1h", "6h", "12h", "24h", "2d", "7d", "30d"]
"10s",
"30s",
"1m",
"5m",
"15m",
"30m",
"1h",
"2h",
"1d"
],
"time_options": [
"5m",
"15m",
"1h",
"6h",
"12h",
"24h",
"2d",
"7d",
"30d"
]
}, },
"timezone": "", "timezone": "",
"title": "Alertmanager", "title": "Alertmanager",
"uid": "eea-9_sik", "uid": "eea-9_sik",
"version": 27 "version": 27
} }
File diff suppressed because it is too large Load Diff
@@ -131,9 +131,7 @@
"justifyMode": "auto", "justifyMode": "auto",
"orientation": "auto", "orientation": "auto",
"reduceOptions": { "reduceOptions": {
"calcs": [ "calcs": ["last"],
"last"
],
"fields": "", "fields": "",
"values": false "values": false
}, },
@@ -198,9 +196,7 @@
"justifyMode": "auto", "justifyMode": "auto",
"orientation": "auto", "orientation": "auto",
"reduceOptions": { "reduceOptions": {
"calcs": [ "calcs": ["last"],
"last"
],
"fields": "", "fields": "",
"values": false "values": false
}, },
@@ -320,9 +316,7 @@
"justifyMode": "auto", "justifyMode": "auto",
"orientation": "auto", "orientation": "auto",
"reduceOptions": { "reduceOptions": {
"calcs": [ "calcs": ["last"],
"last"
],
"fields": "", "fields": "",
"values": false "values": false
}, },
@@ -441,11 +435,7 @@
"id": 93, "id": 93,
"options": { "options": {
"legend": { "legend": {
"calcs": [ "calcs": ["min", "max", "mean"],
"min",
"max",
"mean"
],
"displayMode": "list", "displayMode": "list",
"placement": "right", "placement": "right",
"showLegend": false "showLegend": false
@@ -540,11 +530,7 @@
"id": 96, "id": 96,
"options": { "options": {
"legend": { "legend": {
"calcs": [ "calcs": ["min", "max", "mean"],
"min",
"max",
"mean"
],
"displayMode": "list", "displayMode": "list",
"placement": "right", "placement": "right",
"showLegend": false "showLegend": false
@@ -643,11 +629,7 @@
"id": 74, "id": 74,
"options": { "options": {
"legend": { "legend": {
"calcs": [ "calcs": ["min", "max", "mean"],
"min",
"max",
"mean"
],
"displayMode": "list", "displayMode": "list",
"placement": "right", "placement": "right",
"showLegend": false "showLegend": false
@@ -794,11 +776,7 @@
"id": 84, "id": 84,
"options": { "options": {
"legend": { "legend": {
"calcs": [ "calcs": ["min", "max", "mean"],
"min",
"max",
"mean"
],
"displayMode": "list", "displayMode": "list",
"placement": "right", "placement": "right",
"showLegend": false "showLegend": false
@@ -897,11 +875,7 @@
"id": 75, "id": 75,
"options": { "options": {
"legend": { "legend": {
"calcs": [ "calcs": ["min", "max", "mean"],
"min",
"max",
"mean"
],
"displayMode": "list", "displayMode": "list",
"placement": "right", "placement": "right",
"showLegend": false "showLegend": false
@@ -1000,11 +974,7 @@
"id": 85, "id": 85,
"options": { "options": {
"legend": { "legend": {
"calcs": [ "calcs": ["min", "max", "mean"],
"min",
"max",
"mean"
],
"displayMode": "list", "displayMode": "list",
"placement": "right", "placement": "right",
"showLegend": false "showLegend": false
@@ -1129,11 +1099,7 @@
"id": 59, "id": 59,
"options": { "options": {
"legend": { "legend": {
"calcs": [ "calcs": ["min", "max", "mean"],
"min",
"max",
"mean"
],
"displayMode": "list", "displayMode": "list",
"placement": "right", "placement": "right",
"showLegend": false "showLegend": false
@@ -1244,11 +1210,7 @@
"id": 60, "id": 60,
"options": { "options": {
"legend": { "legend": {
"calcs": [ "calcs": ["min", "max", "mean"],
"min",
"max",
"mean"
],
"displayMode": "list", "displayMode": "list",
"placement": "right", "placement": "right",
"showLegend": false "showLegend": false
@@ -1347,11 +1309,7 @@
"id": 101, "id": 101,
"options": { "options": {
"legend": { "legend": {
"calcs": [ "calcs": ["min", "max", "mean"],
"min",
"max",
"mean"
],
"displayMode": "list", "displayMode": "list",
"placement": "right", "placement": "right",
"showLegend": false "showLegend": false
@@ -1450,11 +1408,7 @@
"id": 102, "id": 102,
"options": { "options": {
"legend": { "legend": {
"calcs": [ "calcs": ["min", "max", "mean"],
"min",
"max",
"mean"
],
"displayMode": "list", "displayMode": "list",
"placement": "right", "placement": "right",
"showLegend": false "showLegend": false
@@ -1589,11 +1543,7 @@
"id": 90, "id": 90,
"options": { "options": {
"legend": { "legend": {
"calcs": [ "calcs": ["min", "max", "mean"],
"min",
"max",
"mean"
],
"displayMode": "list", "displayMode": "list",
"placement": "right", "placement": "right",
"showLegend": false "showLegend": false
@@ -1692,11 +1642,7 @@
"id": 95, "id": 95,
"options": { "options": {
"legend": { "legend": {
"calcs": [ "calcs": ["min", "max", "mean"],
"min",
"max",
"mean"
],
"displayMode": "list", "displayMode": "list",
"placement": "right", "placement": "right",
"showLegend": false "showLegend": false
@@ -1807,11 +1753,7 @@
"id": 73, "id": 73,
"options": { "options": {
"legend": { "legend": {
"calcs": [ "calcs": ["min", "max", "mean"],
"min",
"max",
"mean"
],
"displayMode": "list", "displayMode": "list",
"placement": "right", "placement": "right",
"showLegend": false "showLegend": false
@@ -1910,11 +1852,7 @@
"id": 86, "id": 86,
"options": { "options": {
"legend": { "legend": {
"calcs": [ "calcs": ["min", "max", "mean"],
"min",
"max",
"mean"
],
"displayMode": "list", "displayMode": "list",
"placement": "right", "placement": "right",
"showLegend": false "showLegend": false
@@ -2057,11 +1995,7 @@
"id": 29, "id": 29,
"options": { "options": {
"legend": { "legend": {
"calcs": [ "calcs": ["min", "max", "mean"],
"min",
"max",
"mean"
],
"displayMode": "table", "displayMode": "table",
"placement": "right", "placement": "right",
"showLegend": false "showLegend": false
@@ -2161,11 +2095,7 @@
"id": 51, "id": 51,
"options": { "options": {
"legend": { "legend": {
"calcs": [ "calcs": ["min", "max", "mean"],
"min",
"max",
"mean"
],
"displayMode": "table", "displayMode": "table",
"placement": "right", "placement": "right",
"showLegend": false "showLegend": false
@@ -2290,11 +2220,7 @@
"id": 62, "id": 62,
"options": { "options": {
"legend": { "legend": {
"calcs": [ "calcs": ["min", "max", "mean"],
"min",
"max",
"mean"
],
"displayMode": "table", "displayMode": "table",
"placement": "right", "placement": "right",
"showLegend": true "showLegend": true
@@ -2393,11 +2319,7 @@
"id": 87, "id": 87,
"options": { "options": {
"legend": { "legend": {
"calcs": [ "calcs": ["min", "max", "mean"],
"min",
"max",
"mean"
],
"displayMode": "table", "displayMode": "table",
"placement": "right", "placement": "right",
"showLegend": true "showLegend": true
@@ -3007,10 +2929,7 @@
"revision": 1, "revision": 1,
"schemaVersion": 38, "schemaVersion": 38,
"style": "dark", "style": "dark",
"tags": [ "tags": ["Kubernetes", "Prometheus"],
"Kubernetes",
"Prometheus"
],
"templating": { "templating": {
"list": [ "list": [
{ {
@@ -3147,4 +3066,4 @@
"uid": "k8s_addons_prometheus", "uid": "k8s_addons_prometheus",
"version": 3, "version": 3,
"weekStart": "" "weekStart": ""
} }
@@ -1,47 +1,47 @@
{ {
"__inputs": [ "__inputs": [
{ {
"name": "DS_PROMETHEUS", "name": "DS_PROMETHEUS",
"label": "Prometheus", "label": "Prometheus",
"description": "", "description": "",
"type": "datasource", "type": "datasource",
"pluginId": "prometheus", "pluginId": "prometheus",
"pluginName": "Prometheus" "pluginName": "Prometheus"
} }
], ],
"__elements": [], "__elements": [],
"__requires": [ "__requires": [
{ {
"type": "grafana", "type": "grafana",
"id": "grafana", "id": "grafana",
"name": "Grafana", "name": "Grafana",
"version": "8.5.0" "version": "8.5.0"
}, },
{ {
"type": "datasource", "type": "datasource",
"id": "prometheus", "id": "prometheus",
"name": "Prometheus", "name": "Prometheus",
"version": "5.0.0" "version": "5.0.0"
}, },
{ {
"type": "panel", "type": "panel",
"id": "timeseries", "id": "timeseries",
"name": "Time series", "name": "Time series",
"version": "" "version": ""
}, },
{ {
"type": "panel", "type": "panel",
"id": "stat", "id": "stat",
"name": "Stat", "name": "Stat",
"version": "" "version": ""
}, },
{ {
"type": "panel", "type": "panel",
"id": "table", "id": "table",
"name": "Table", "name": "Table",
"version": "" "version": ""
} }
], ],
"annotations": { "annotations": {
"list": [ "list": [
{ {
@@ -129,9 +129,7 @@
"justifyMode": "auto", "justifyMode": "auto",
"orientation": "auto", "orientation": "auto",
"reduceOptions": { "reduceOptions": {
"calcs": [ "calcs": ["last"],
"last"
],
"fields": "", "fields": "",
"values": false "values": false
}, },
@@ -197,9 +195,7 @@
"justifyMode": "auto", "justifyMode": "auto",
"orientation": "auto", "orientation": "auto",
"reduceOptions": { "reduceOptions": {
"calcs": [ "calcs": ["last"],
"last"
],
"fields": "", "fields": "",
"values": false "values": false
}, },
@@ -265,9 +261,7 @@
"justifyMode": "auto", "justifyMode": "auto",
"orientation": "auto", "orientation": "auto",
"reduceOptions": { "reduceOptions": {
"calcs": [ "calcs": ["last"],
"last"
],
"fields": "", "fields": "",
"values": false "values": false
}, },
@@ -333,9 +327,7 @@
"justifyMode": "auto", "justifyMode": "auto",
"orientation": "auto", "orientation": "auto",
"reduceOptions": { "reduceOptions": {
"calcs": [ "calcs": ["last"],
"last"
],
"fields": "", "fields": "",
"values": false "values": false
}, },
@@ -401,9 +393,7 @@
"justifyMode": "auto", "justifyMode": "auto",
"orientation": "auto", "orientation": "auto",
"reduceOptions": { "reduceOptions": {
"calcs": [ "calcs": ["last"],
"last"
],
"fields": "", "fields": "",
"values": false "values": false
}, },
@@ -469,9 +459,7 @@
"justifyMode": "auto", "justifyMode": "auto",
"orientation": "auto", "orientation": "auto",
"reduceOptions": { "reduceOptions": {
"calcs": [ "calcs": ["last"],
"last"
],
"fields": "", "fields": "",
"values": false "values": false
}, },
@@ -863,12 +851,8 @@
"options": { "options": {
"footer": { "footer": {
"enablePagination": true, "enablePagination": true,
"fields": [ "fields": ["Value"],
"Value" "reducer": ["sum"],
],
"reducer": [
"sum"
],
"show": false "show": false
}, },
"showHeader": true, "showHeader": true,
@@ -1093,9 +1077,7 @@
"footer": { "footer": {
"enablePagination": true, "enablePagination": true,
"fields": "", "fields": "",
"reducer": [ "reducer": ["sum"],
"sum"
],
"show": false "show": false
}, },
"showHeader": true, "showHeader": true,
@@ -1182,9 +1164,7 @@
"operation": "groupby" "operation": "groupby"
}, },
"Value": { "Value": {
"aggregations": [ "aggregations": ["lastNotNull"]
"lastNotNull"
]
}, },
"Vulnerability": { "Vulnerability": {
"aggregations": [], "aggregations": [],
@@ -1274,9 +1254,7 @@
"justifyMode": "auto", "justifyMode": "auto",
"orientation": "auto", "orientation": "auto",
"reduceOptions": { "reduceOptions": {
"calcs": [ "calcs": ["last"],
"last"
],
"fields": "", "fields": "",
"values": false "values": false
}, },
@@ -1342,9 +1320,7 @@
"justifyMode": "auto", "justifyMode": "auto",
"orientation": "auto", "orientation": "auto",
"reduceOptions": { "reduceOptions": {
"calcs": [ "calcs": ["last"],
"last"
],
"fields": "", "fields": "",
"values": false "values": false
}, },
@@ -1410,9 +1386,7 @@
"justifyMode": "auto", "justifyMode": "auto",
"orientation": "auto", "orientation": "auto",
"reduceOptions": { "reduceOptions": {
"calcs": [ "calcs": ["last"],
"last"
],
"fields": "", "fields": "",
"values": false "values": false
}, },
@@ -1478,9 +1452,7 @@
"justifyMode": "auto", "justifyMode": "auto",
"orientation": "auto", "orientation": "auto",
"reduceOptions": { "reduceOptions": {
"calcs": [ "calcs": ["last"],
"last"
],
"fields": "", "fields": "",
"values": false "values": false
}, },
@@ -1546,9 +1518,7 @@
"justifyMode": "auto", "justifyMode": "auto",
"orientation": "auto", "orientation": "auto",
"reduceOptions": { "reduceOptions": {
"calcs": [ "calcs": ["last"],
"last"
],
"fields": "", "fields": "",
"values": false "values": false
}, },
@@ -1882,9 +1852,7 @@
"justifyMode": "auto", "justifyMode": "auto",
"orientation": "auto", "orientation": "auto",
"reduceOptions": { "reduceOptions": {
"calcs": [ "calcs": ["last"],
"last"
],
"fields": "", "fields": "",
"values": false "values": false
}, },
@@ -1950,9 +1918,7 @@
"justifyMode": "auto", "justifyMode": "auto",
"orientation": "auto", "orientation": "auto",
"reduceOptions": { "reduceOptions": {
"calcs": [ "calcs": ["last"],
"last"
],
"fields": "", "fields": "",
"values": false "values": false
}, },
@@ -2018,9 +1984,7 @@
"justifyMode": "auto", "justifyMode": "auto",
"orientation": "auto", "orientation": "auto",
"reduceOptions": { "reduceOptions": {
"calcs": [ "calcs": ["last"],
"last"
],
"fields": "", "fields": "",
"values": false "values": false
}, },
@@ -2086,9 +2050,7 @@
"justifyMode": "auto", "justifyMode": "auto",
"orientation": "auto", "orientation": "auto",
"reduceOptions": { "reduceOptions": {
"calcs": [ "calcs": ["last"],
"last"
],
"fields": "", "fields": "",
"values": false "values": false
}, },
@@ -2154,9 +2116,7 @@
"justifyMode": "auto", "justifyMode": "auto",
"orientation": "auto", "orientation": "auto",
"reduceOptions": { "reduceOptions": {
"calcs": [ "calcs": ["last"],
"last"
],
"fields": "", "fields": "",
"values": false "values": false
}, },
@@ -2550,12 +2510,7 @@
"refresh": "30s", "refresh": "30s",
"schemaVersion": 37, "schemaVersion": 37,
"style": "dark", "style": "dark",
"tags": [ "tags": ["Prometheus", "Addons", "Trivy", "Trivy-operator"],
"Prometheus",
"Addons",
"Trivy",
"Trivy-operator"
],
"templating": { "templating": {
"list": [ "list": [
{ {
@@ -2607,12 +2562,8 @@
{ {
"current": { "current": {
"selected": true, "selected": true,
"text": [ "text": ["All"],
"All" "value": ["$__all"]
],
"value": [
"$__all"
]
}, },
"datasource": { "datasource": {
"type": "prometheus", "type": "prometheus",
@@ -114,9 +114,7 @@
"justifyMode": "auto", "justifyMode": "auto",
"orientation": "horizontal", "orientation": "horizontal",
"reduceOptions": { "reduceOptions": {
"calcs": [ "calcs": ["lastNotNull"],
"lastNotNull"
],
"fields": "", "fields": "",
"values": false "values": false
}, },
@@ -195,9 +193,7 @@
"footer": { "footer": {
"countRows": false, "countRows": false,
"fields": "", "fields": "",
"reducer": [ "reducer": ["sum"],
"sum"
],
"show": false "show": false
}, },
"showHeader": true, "showHeader": true,
@@ -227,14 +223,7 @@
{ {
"id": "labelsToFields", "id": "labelsToFields",
"options": { "options": {
"keepLabels": [ "keepLabels": ["group", "job", "removed_release", "resource", "version", "name"],
"group",
"job",
"removed_release",
"resource",
"version",
"name"
],
"mode": "columns" "mode": "columns"
} }
}, },
@@ -268,9 +257,7 @@
"options": { "options": {
"fields": { "fields": {
"group": { "group": {
"aggregations": [ "aggregations": ["lastNotNull"],
"lastNotNull"
],
"operation": "groupby" "operation": "groupby"
}, },
"job": { "job": {
@@ -278,9 +265,7 @@
"operation": "groupby" "operation": "groupby"
}, },
"namespace": { "namespace": {
"aggregations": [ "aggregations": ["lastNotNull"],
"lastNotNull"
],
"operation": "groupby" "operation": "groupby"
}, },
"removed_release": { "removed_release": {
@@ -288,9 +273,7 @@
"operation": "groupby" "operation": "groupby"
}, },
"resource": { "resource": {
"aggregations": [ "aggregations": ["lastNotNull"],
"lastNotNull"
],
"operation": "groupby" "operation": "groupby"
}, },
"version": { "version": {
@@ -1248,10 +1231,7 @@
"refresh": "30s", "refresh": "30s",
"schemaVersion": 38, "schemaVersion": 38,
"style": "dark", "style": "dark",
"tags": [ "tags": ["Kubernetes", "Prometheus"],
"Kubernetes",
"Prometheus"
],
"templating": { "templating": {
"list": [ "list": [
{ {
@@ -114,9 +114,7 @@
"justifyMode": "auto", "justifyMode": "auto",
"orientation": "vertical", "orientation": "vertical",
"reduceOptions": { "reduceOptions": {
"calcs": [ "calcs": ["lastNotNull"],
"lastNotNull"
],
"fields": "", "fields": "",
"values": false "values": false
}, },
@@ -1431,10 +1429,7 @@
], ],
"refresh": "30s", "refresh": "30s",
"schemaVersion": 38, "schemaVersion": 38,
"tags": [ "tags": ["Kubernetes", "Prometheus"],
"Kubernetes",
"Prometheus"
],
"templating": { "templating": {
"list": [ "list": [
{ {
@@ -1595,12 +1590,8 @@
{ {
"current": { "current": {
"selected": true, "selected": true,
"text": [ "text": ["coredns"],
"coredns" "value": ["coredns"]
],
"value": [
"coredns"
]
}, },
"definition": "label_values(coredns_build_info{cluster=\"$cluster\"},job)", "definition": "label_values(coredns_build_info{cluster=\"$cluster\"},job)",
"hide": 0, "hide": 0,
@@ -134,9 +134,7 @@
"namePlacement": "auto", "namePlacement": "auto",
"orientation": "horizontal", "orientation": "horizontal",
"reduceOptions": { "reduceOptions": {
"calcs": [ "calcs": ["lastNotNull"],
"lastNotNull"
],
"fields": "", "fields": "",
"values": false "values": false
}, },
@@ -234,9 +232,7 @@
"namePlacement": "auto", "namePlacement": "auto",
"orientation": "horizontal", "orientation": "horizontal",
"reduceOptions": { "reduceOptions": {
"calcs": [ "calcs": ["lastNotNull"],
"lastNotNull"
],
"fields": "", "fields": "",
"values": false "values": false
}, },
@@ -323,9 +319,7 @@
"justifyMode": "auto", "justifyMode": "auto",
"orientation": "auto", "orientation": "auto",
"reduceOptions": { "reduceOptions": {
"calcs": [ "calcs": ["last"],
"last"
],
"fields": "", "fields": "",
"values": false "values": false
}, },
@@ -421,11 +415,7 @@
"id": 52, "id": 52,
"options": { "options": {
"legend": { "legend": {
"calcs": [ "calcs": ["min", "max", "mean"],
"min",
"max",
"mean"
],
"displayMode": "table", "displayMode": "table",
"placement": "right", "placement": "right",
"showLegend": true, "showLegend": true,
@@ -631,9 +621,7 @@
"justifyMode": "auto", "justifyMode": "auto",
"orientation": "auto", "orientation": "auto",
"reduceOptions": { "reduceOptions": {
"calcs": [ "calcs": ["last"],
"last"
],
"fields": "", "fields": "",
"values": false "values": false
}, },
@@ -694,9 +682,7 @@
"justifyMode": "center", "justifyMode": "center",
"orientation": "auto", "orientation": "auto",
"reduceOptions": { "reduceOptions": {
"calcs": [ "calcs": ["lastNotNull"],
"lastNotNull"
],
"fields": "", "fields": "",
"values": false "values": false
}, },
@@ -796,9 +782,7 @@
"justifyMode": "auto", "justifyMode": "auto",
"orientation": "auto", "orientation": "auto",
"reduceOptions": { "reduceOptions": {
"calcs": [ "calcs": ["lastNotNull"],
"lastNotNull"
],
"fields": "", "fields": "",
"values": false "values": false
}, },
@@ -897,9 +881,7 @@
"justifyMode": "auto", "justifyMode": "auto",
"orientation": "auto", "orientation": "auto",
"reduceOptions": { "reduceOptions": {
"calcs": [ "calcs": ["last"],
"last"
],
"fields": "", "fields": "",
"values": false "values": false
}, },
@@ -1121,12 +1103,7 @@
"id": 55, "id": 55,
"options": { "options": {
"legend": { "legend": {
"calcs": [ "calcs": ["mean", "lastNotNull", "max", "min"],
"mean",
"lastNotNull",
"max",
"min"
],
"displayMode": "hidden", "displayMode": "hidden",
"placement": "right", "placement": "right",
"showLegend": false "showLegend": false
@@ -1229,11 +1206,7 @@
"id": 46, "id": 46,
"options": { "options": {
"legend": { "legend": {
"calcs": [ "calcs": ["min", "max", "mean"],
"min",
"max",
"mean"
],
"displayMode": "table", "displayMode": "table",
"placement": "right", "placement": "right",
"showLegend": true, "showLegend": true,
@@ -1332,11 +1305,7 @@
"id": 50, "id": 50,
"options": { "options": {
"legend": { "legend": {
"calcs": [ "calcs": ["min", "max", "mean"],
"min",
"max",
"mean"
],
"displayMode": "table", "displayMode": "table",
"placement": "right", "placement": "right",
"showLegend": true, "showLegend": true,
@@ -1432,11 +1401,7 @@
"id": 54, "id": 54,
"options": { "options": {
"legend": { "legend": {
"calcs": [ "calcs": ["min", "max", "mean"],
"min",
"max",
"mean"
],
"displayMode": "table", "displayMode": "table",
"placement": "right", "placement": "right",
"showLegend": true, "showLegend": true,
@@ -1531,11 +1496,7 @@
"id": 73, "id": 73,
"options": { "options": {
"legend": { "legend": {
"calcs": [ "calcs": ["min", "max", "mean"],
"min",
"max",
"mean"
],
"displayMode": "table", "displayMode": "table",
"placement": "right", "placement": "right",
"showLegend": true, "showLegend": true,
@@ -1637,11 +1598,7 @@
"id": 82, "id": 82,
"options": { "options": {
"legend": { "legend": {
"calcs": [ "calcs": ["min", "max", "mean"],
"min",
"max",
"mean"
],
"displayMode": "table", "displayMode": "table",
"placement": "right", "placement": "right",
"showLegend": true, "showLegend": true,
@@ -1743,11 +1700,7 @@
"id": 83, "id": 83,
"options": { "options": {
"legend": { "legend": {
"calcs": [ "calcs": ["min", "max", "mean"],
"min",
"max",
"mean"
],
"displayMode": "table", "displayMode": "table",
"placement": "right", "placement": "right",
"showLegend": true, "showLegend": true,
@@ -1857,11 +1810,7 @@
"id": 84, "id": 84,
"options": { "options": {
"legend": { "legend": {
"calcs": [ "calcs": ["min", "max", "mean"],
"min",
"max",
"mean"
],
"displayMode": "table", "displayMode": "table",
"placement": "right", "placement": "right",
"showLegend": true, "showLegend": true,
@@ -1970,11 +1919,7 @@
"id": 85, "id": 85,
"options": { "options": {
"legend": { "legend": {
"calcs": [ "calcs": ["min", "max", "mean"],
"min",
"max",
"mean"
],
"displayMode": "table", "displayMode": "table",
"placement": "right", "placement": "right",
"showLegend": true, "showLegend": true,
@@ -2072,11 +2017,7 @@
"id": 87, "id": 87,
"options": { "options": {
"legend": { "legend": {
"calcs": [ "calcs": ["min", "max", "mean"],
"min",
"max",
"mean"
],
"displayMode": "table", "displayMode": "table",
"placement": "right", "placement": "right",
"showLegend": true, "showLegend": true,
@@ -2174,11 +2115,7 @@
"id": 88, "id": 88,
"options": { "options": {
"legend": { "legend": {
"calcs": [ "calcs": ["min", "max", "mean"],
"min",
"max",
"mean"
],
"displayMode": "table", "displayMode": "table",
"placement": "right", "placement": "right",
"showLegend": true, "showLegend": true,
@@ -2880,10 +2817,7 @@
], ],
"refresh": "30s", "refresh": "30s",
"schemaVersion": 39, "schemaVersion": 39,
"tags": [ "tags": ["Kubernetes", "Prometheus"],
"Kubernetes",
"Prometheus"
],
"templating": { "templating": {
"list": [ "list": [
{ {
@@ -133,9 +133,7 @@
"minVizWidth": 75, "minVizWidth": 75,
"orientation": "auto", "orientation": "auto",
"reduceOptions": { "reduceOptions": {
"calcs": [ "calcs": ["lastNotNull"],
"lastNotNull"
],
"fields": "", "fields": "",
"values": false "values": false
}, },
@@ -209,9 +207,7 @@
"minVizWidth": 75, "minVizWidth": 75,
"orientation": "auto", "orientation": "auto",
"reduceOptions": { "reduceOptions": {
"calcs": [ "calcs": ["lastNotNull"],
"lastNotNull"
],
"fields": "", "fields": "",
"values": false "values": false
}, },
@@ -307,11 +303,7 @@
"id": 32, "id": 32,
"options": { "options": {
"legend": { "legend": {
"calcs": [ "calcs": ["min", "max", "mean"],
"min",
"max",
"mean"
],
"displayMode": "table", "displayMode": "table",
"placement": "right", "placement": "right",
"showLegend": true, "showLegend": true,
@@ -475,9 +467,7 @@
"justifyMode": "center", "justifyMode": "center",
"orientation": "auto", "orientation": "auto",
"reduceOptions": { "reduceOptions": {
"calcs": [ "calcs": ["lastNotNull"],
"lastNotNull"
],
"fields": "", "fields": "",
"values": false "values": false
}, },
@@ -577,9 +567,7 @@
"justifyMode": "auto", "justifyMode": "auto",
"orientation": "auto", "orientation": "auto",
"reduceOptions": { "reduceOptions": {
"calcs": [ "calcs": ["lastNotNull"],
"lastNotNull"
],
"fields": "", "fields": "",
"values": false "values": false
}, },
@@ -931,11 +919,7 @@
"id": 68, "id": 68,
"options": { "options": {
"legend": { "legend": {
"calcs": [ "calcs": ["min", "max", "mean"],
"min",
"max",
"mean"
],
"displayMode": "table", "displayMode": "table",
"placement": "right", "placement": "right",
"showLegend": true, "showLegend": true,
@@ -1047,11 +1031,7 @@
"id": 70, "id": 70,
"options": { "options": {
"legend": { "legend": {
"calcs": [ "calcs": ["min", "max", "mean"],
"min",
"max",
"mean"
],
"displayMode": "table", "displayMode": "table",
"placement": "right", "placement": "right",
"showLegend": true, "showLegend": true,
@@ -1162,11 +1142,7 @@
"id": 72, "id": 72,
"options": { "options": {
"legend": { "legend": {
"calcs": [ "calcs": ["min", "max", "mean"],
"min",
"max",
"mean"
],
"displayMode": "table", "displayMode": "table",
"placement": "right", "placement": "right",
"showLegend": true, "showLegend": true,
@@ -1266,11 +1242,7 @@
"id": 74, "id": 74,
"options": { "options": {
"legend": { "legend": {
"calcs": [ "calcs": ["min", "max", "mean"],
"min",
"max",
"mean"
],
"displayMode": "table", "displayMode": "table",
"placement": "right", "placement": "right",
"showLegend": true, "showLegend": true,
@@ -1370,11 +1342,7 @@
"id": 75, "id": 75,
"options": { "options": {
"legend": { "legend": {
"calcs": [ "calcs": ["min", "max", "mean"],
"min",
"max",
"mean"
],
"displayMode": "table", "displayMode": "table",
"placement": "right", "placement": "right",
"showLegend": true, "showLegend": true,
@@ -2154,10 +2122,7 @@
], ],
"refresh": "30s", "refresh": "30s",
"schemaVersion": 39, "schemaVersion": 39,
"tags": [ "tags": ["Kubernetes", "Prometheus"],
"Kubernetes",
"Prometheus"
],
"templating": { "templating": {
"list": [ "list": [
{ {
@@ -139,9 +139,7 @@
"minVizWidth": 75, "minVizWidth": 75,
"orientation": "auto", "orientation": "auto",
"reduceOptions": { "reduceOptions": {
"calcs": [ "calcs": ["lastNotNull"],
"lastNotNull"
],
"fields": "", "fields": "",
"values": false "values": false
}, },
@@ -213,9 +211,7 @@
"minVizWidth": 75, "minVizWidth": 75,
"orientation": "auto", "orientation": "auto",
"reduceOptions": { "reduceOptions": {
"calcs": [ "calcs": ["lastNotNull"],
"lastNotNull"
],
"fields": "", "fields": "",
"values": false "values": false
}, },
@@ -277,9 +273,7 @@
"justifyMode": "auto", "justifyMode": "auto",
"orientation": "auto", "orientation": "auto",
"reduceOptions": { "reduceOptions": {
"calcs": [ "calcs": ["lastNotNull"],
"lastNotNull"
],
"fields": "", "fields": "",
"values": false "values": false
}, },
@@ -420,9 +414,7 @@
"footer": { "footer": {
"countRows": false, "countRows": false,
"fields": "", "fields": "",
"reducer": [ "reducer": ["sum"],
"sum"
],
"show": false "show": false
}, },
"showHeader": true, "showHeader": true,
@@ -506,9 +498,7 @@
"operation": "groupby" "operation": "groupby"
}, },
"namespace": { "namespace": {
"aggregations": [ "aggregations": ["last"],
"last"
],
"operation": "groupby" "operation": "groupby"
}, },
"pod": { "pod": {
@@ -566,9 +556,7 @@
"justifyMode": "auto", "justifyMode": "auto",
"orientation": "auto", "orientation": "auto",
"reduceOptions": { "reduceOptions": {
"calcs": [ "calcs": ["lastNotNull"],
"lastNotNull"
],
"fields": "", "fields": "",
"values": false "values": false
}, },
@@ -631,9 +619,7 @@
"justifyMode": "auto", "justifyMode": "auto",
"orientation": "auto", "orientation": "auto",
"reduceOptions": { "reduceOptions": {
"calcs": [ "calcs": ["lastNotNull"],
"lastNotNull"
],
"fields": "", "fields": "",
"values": false "values": false
}, },
@@ -695,9 +681,7 @@
"justifyMode": "auto", "justifyMode": "auto",
"orientation": "auto", "orientation": "auto",
"reduceOptions": { "reduceOptions": {
"calcs": [ "calcs": ["lastNotNull"],
"lastNotNull"
],
"fields": "", "fields": "",
"values": false "values": false
}, },
@@ -760,9 +744,7 @@
"justifyMode": "auto", "justifyMode": "auto",
"orientation": "auto", "orientation": "auto",
"reduceOptions": { "reduceOptions": {
"calcs": [ "calcs": ["lastNotNull"],
"lastNotNull"
],
"fields": "", "fields": "",
"values": false "values": false
}, },
@@ -833,9 +815,7 @@
"justifyMode": "auto", "justifyMode": "auto",
"orientation": "auto", "orientation": "auto",
"reduceOptions": { "reduceOptions": {
"calcs": [ "calcs": ["lastNotNull"],
"lastNotNull"
],
"fields": "", "fields": "",
"values": false "values": false
}, },
@@ -1416,11 +1396,7 @@
"id": 66, "id": 66,
"options": { "options": {
"legend": { "legend": {
"calcs": [ "calcs": ["min", "max", "mean"],
"min",
"max",
"mean"
],
"displayMode": "table", "displayMode": "table",
"placement": "right", "placement": "right",
"showLegend": true, "showLegend": true,
@@ -2795,9 +2771,7 @@
"footer": { "footer": {
"countRows": false, "countRows": false,
"fields": "", "fields": "",
"reducer": [ "reducer": ["sum"],
"sum"
],
"show": false "show": false
}, },
"showHeader": true, "showHeader": true,
@@ -2839,21 +2813,15 @@
"options": { "options": {
"fields": { "fields": {
"Value": { "Value": {
"aggregations": [ "aggregations": ["lastNotNull"],
"lastNotNull"
],
"operation": "aggregate" "operation": "aggregate"
}, },
"Value #A": { "Value #A": {
"aggregations": [ "aggregations": ["lastNotNull"],
"lastNotNull"
],
"operation": "aggregate" "operation": "aggregate"
}, },
"Value #B": { "Value #B": {
"aggregations": [ "aggregations": ["lastNotNull"],
"lastNotNull"
],
"operation": "aggregate" "operation": "aggregate"
}, },
"persistentvolumeclaim": { "persistentvolumeclaim": {
@@ -3790,10 +3758,7 @@
], ],
"refresh": "30s", "refresh": "30s",
"schemaVersion": 39, "schemaVersion": 39,
"tags": [ "tags": ["Kubernetes", "Prometheus"],
"Kubernetes",
"Prometheus"
],
"templating": { "templating": {
"list": [ "list": [
{ {
@@ -137,9 +137,7 @@
"justifyMode": "auto", "justifyMode": "auto",
"orientation": "auto", "orientation": "auto",
"reduceOptions": { "reduceOptions": {
"calcs": [ "calcs": ["mean"],
"mean"
],
"fields": "", "fields": "",
"values": false "values": false
}, },
@@ -205,9 +203,7 @@
"justifyMode": "auto", "justifyMode": "auto",
"orientation": "auto", "orientation": "auto",
"reduceOptions": { "reduceOptions": {
"calcs": [ "calcs": ["mean"],
"mean"
],
"fields": "", "fields": "",
"values": false "values": false
}, },
@@ -267,9 +263,7 @@
"justifyMode": "auto", "justifyMode": "auto",
"orientation": "auto", "orientation": "auto",
"reduceOptions": { "reduceOptions": {
"calcs": [ "calcs": ["mean"],
"mean"
],
"fields": "", "fields": "",
"values": false "values": false
}, },
@@ -329,9 +323,7 @@
"justifyMode": "auto", "justifyMode": "auto",
"orientation": "auto", "orientation": "auto",
"reduceOptions": { "reduceOptions": {
"calcs": [ "calcs": ["mean"],
"mean"
],
"fields": "", "fields": "",
"values": false "values": false
}, },
@@ -660,9 +652,7 @@
"minVizWidth": 75, "minVizWidth": 75,
"orientation": "auto", "orientation": "auto",
"reduceOptions": { "reduceOptions": {
"calcs": [ "calcs": ["last"],
"last"
],
"fields": "", "fields": "",
"values": false "values": false
}, },
@@ -732,9 +722,7 @@
"minVizWidth": 75, "minVizWidth": 75,
"orientation": "auto", "orientation": "auto",
"reduceOptions": { "reduceOptions": {
"calcs": [ "calcs": ["last"],
"last"
],
"fields": "", "fields": "",
"values": false "values": false
}, },
@@ -808,9 +796,7 @@
"minVizWidth": 75, "minVizWidth": 75,
"orientation": "auto", "orientation": "auto",
"reduceOptions": { "reduceOptions": {
"calcs": [ "calcs": ["last"],
"last"
],
"fields": "", "fields": "",
"values": false "values": false
}, },
@@ -880,9 +866,7 @@
"minVizWidth": 75, "minVizWidth": 75,
"orientation": "auto", "orientation": "auto",
"reduceOptions": { "reduceOptions": {
"calcs": [ "calcs": ["last"],
"last"
],
"fields": "", "fields": "",
"values": false "values": false
}, },
@@ -1000,9 +984,7 @@
"footer": { "footer": {
"countRows": false, "countRows": false,
"fields": "", "fields": "",
"reducer": [ "reducer": ["sum"],
"sum"
],
"show": false "show": false
}, },
"showHeader": true, "showHeader": true,
@@ -1532,11 +1514,7 @@
"id": 29, "id": 29,
"options": { "options": {
"legend": { "legend": {
"calcs": [ "calcs": ["min", "max", "mean"],
"min",
"max",
"mean"
],
"displayMode": "table", "displayMode": "table",
"placement": "right", "placement": "right",
"showLegend": true "showLegend": true
@@ -1638,11 +1616,7 @@
"id": 51, "id": 51,
"options": { "options": {
"legend": { "legend": {
"calcs": [ "calcs": ["min", "max", "mean"],
"min",
"max",
"mean"
],
"displayMode": "table", "displayMode": "table",
"placement": "right", "placement": "right",
"showLegend": true "showLegend": true
@@ -1744,11 +1718,7 @@
"id": 59, "id": 59,
"options": { "options": {
"legend": { "legend": {
"calcs": [ "calcs": ["min", "max", "mean"],
"min",
"max",
"mean"
],
"displayMode": "table", "displayMode": "table",
"placement": "right", "placement": "right",
"showLegend": true, "showLegend": true,
@@ -2475,10 +2445,7 @@
], ],
"refresh": "30s", "refresh": "30s",
"schemaVersion": 38, "schemaVersion": 38,
"tags": [ "tags": ["Kubernetes", "Prometheus"],
"Kubernetes",
"Prometheus"
],
"templating": { "templating": {
"list": [ "list": [
{ {
+3 -3
View File
@@ -12,10 +12,10 @@ datasources:
manageAlerts: true manageAlerts: true
prometheusType: Prometheus prometheusType: Prometheus
prometheusVersion: 2.49.0 prometheusVersion: 2.49.0
cacheLevel: 'High' cacheLevel: "High"
disableRecordingRules: false 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. # 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. # but might be helpful for instances that have inconsistent results for recent data.
incrementalQueryOverlapWindow: 10m incrementalQueryOverlapWindow: 10m
+2 -3
View File
@@ -2,6 +2,5 @@
## Alert Rules ## 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
@@ -1,14 +1,13 @@
groups: groups:
- name: EmbeddedExporter
- name: EmbeddedExporter rules:
- alert: CorednsPanicCount
rules: expr: "increase(coredns_panics_total[1m]) > 0"
for: 0m
- alert: CorednsPanicCount labels:
expr: 'increase(coredns_panics_total[1m]) > 0' severity: critical
for: 0m annotations:
labels: summary: CoreDNS Panic Count (instance {{ $labels.instance }})
severity: critical description:
annotations: "Number of CoreDNS panics encountered\n VALUE = {{ $value }}\n LABELS = {{ $labels }}"
summary: CoreDNS Panic Count (instance {{ $labels.instance }})
description: "Number of CoreDNS panics encountered\n VALUE = {{ $value }}\n LABELS = {{ $labels }}"
@@ -1,122 +1,162 @@
groups: 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 - alert: EtcdHighNumberOfLeaderChanges
expr: 'count(etcd_server_id) % 2 == 0' expr: "increase(etcd_server_leader_changes_seen_total[10m]) > 2"
for: 0m for: 0m
labels: labels:
severity: critical severity: warning
annotations: annotations:
summary: Etcd insufficient Members (instance {{ $labels.instance }}) summary: Etcd high number of leader changes (instance {{ $labels.instance }})
description: "Etcd cluster should have an odd number of members\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" description:
"Etcd leader changed more than 2 times during 10 minutes\n VALUE = {{ $value
}}\n LABELS = {{ $labels }}"
- alert: EtcdNoLeader - alert: EtcdHighNumberOfFailedGrpcRequests
expr: 'etcd_server_has_leader == 0' expr:
for: 0m 'sum(rate(grpc_server_handled_total{grpc_code!="OK"}[1m])) BY (grpc_service, grpc_method)
labels: / sum(rate(grpc_server_handled_total[1m])) BY (grpc_service, grpc_method) > 0.01'
severity: critical for: 2m
annotations: labels:
summary: Etcd no Leader (instance {{ $labels.instance }}) severity: warning
description: "Etcd cluster have no leader\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" 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 - alert: EtcdHighNumberOfFailedGrpcRequests
expr: 'increase(etcd_server_leader_changes_seen_total[10m]) > 2' expr:
for: 0m 'sum(rate(grpc_server_handled_total{grpc_code!="OK"}[1m])) BY (grpc_service, grpc_method)
labels: / sum(rate(grpc_server_handled_total[1m])) BY (grpc_service, grpc_method) > 0.05'
severity: warning for: 2m
annotations: labels:
summary: Etcd high number of leader changes (instance {{ $labels.instance }}) severity: critical
description: "Etcd leader changed more than 2 times during 10 minutes\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" 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 - alert: EtcdGrpcRequestsSlow
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' expr:
for: 2m 'histogram_quantile(0.99,
labels: sum(rate(grpc_server_handling_seconds_bucket{grpc_type="unary"}[1m])) by (grpc_service,
severity: warning grpc_method, le)) > 0.15'
annotations: for: 2m
summary: Etcd high number of failed GRPC requests (instance {{ $labels.instance }}) labels:
description: "More than 1% GRPC request failure detected in Etcd\n VALUE = {{ $value }}\n LABELS = {{ $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 - alert: EtcdHighNumberOfFailedHttpRequests
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' expr:
for: 2m "sum(rate(etcd_http_failed_total[1m])) BY (method) /
labels: sum(rate(etcd_http_received_total[1m])) BY (method) > 0.01"
severity: critical for: 2m
annotations: labels:
summary: Etcd high number of failed GRPC requests (instance {{ $labels.instance }}) severity: warning
description: "More than 5% GRPC request failure detected in Etcd\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" 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 - alert: EtcdHighNumberOfFailedHttpRequests
expr: 'histogram_quantile(0.99, sum(rate(grpc_server_handling_seconds_bucket{grpc_type="unary"}[1m])) by (grpc_service, grpc_method, le)) > 0.15' expr:
for: 2m "sum(rate(etcd_http_failed_total[1m])) BY (method) /
labels: sum(rate(etcd_http_received_total[1m])) BY (method) > 0.05"
severity: warning for: 2m
annotations: labels:
summary: Etcd GRPC requests slow (instance {{ $labels.instance }}) severity: critical
description: "GRPC requests slowing down, 99th percentile is over 0.15s\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" 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 - alert: EtcdHttpRequestsSlow
expr: 'sum(rate(etcd_http_failed_total[1m])) BY (method) / sum(rate(etcd_http_received_total[1m])) BY (method) > 0.01' expr:
for: 2m "histogram_quantile(0.99, rate(etcd_http_successful_duration_seconds_bucket[1m])) > 0.15"
labels: for: 2m
severity: warning labels:
annotations: severity: warning
summary: Etcd high number of failed HTTP requests (instance {{ $labels.instance }}) annotations:
description: "More than 1% HTTP failure detected in Etcd\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" 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 - alert: EtcdMemberCommunicationSlow
expr: 'sum(rate(etcd_http_failed_total[1m])) BY (method) / sum(rate(etcd_http_received_total[1m])) BY (method) > 0.05' expr:
for: 2m "histogram_quantile(0.99, rate(etcd_network_peer_round_trip_time_seconds_bucket[1m])) >
labels: 0.15"
severity: critical for: 2m
annotations: labels:
summary: Etcd high number of failed HTTP requests (instance {{ $labels.instance }}) severity: warning
description: "More than 5% HTTP failure detected in Etcd\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" 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 - alert: EtcdHighNumberOfFailedProposals
expr: 'histogram_quantile(0.99, rate(etcd_http_successful_duration_seconds_bucket[1m])) > 0.15' expr: "increase(etcd_server_proposals_failed_total[1h]) > 5"
for: 2m for: 2m
labels: labels:
severity: warning severity: warning
annotations: annotations:
summary: Etcd HTTP requests slow (instance {{ $labels.instance }}) summary: Etcd high number of failed proposals (instance {{ $labels.instance }})
description: "HTTP requests slowing down, 99th percentile is over 0.15s\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" description:
"Etcd server got more than 5 failed proposals past hour\n VALUE = {{ $value
}}\n LABELS = {{ $labels }}"
- alert: EtcdMemberCommunicationSlow - alert: EtcdHighFsyncDurations
expr: 'histogram_quantile(0.99, rate(etcd_network_peer_round_trip_time_seconds_bucket[1m])) > 0.15' expr:
for: 2m "histogram_quantile(0.99, rate(etcd_disk_wal_fsync_duration_seconds_bucket[1m])) > 0.5"
labels: for: 2m
severity: warning labels:
annotations: severity: warning
summary: Etcd member communication slow (instance {{ $labels.instance }}) annotations:
description: "Etcd member communication slowing down, 99th percentile is over 0.15s\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" 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 - alert: EtcdHighCommitDurations
expr: 'increase(etcd_server_proposals_failed_total[1h]) > 5' expr:
for: 2m "histogram_quantile(0.99, rate(etcd_disk_backend_commit_duration_seconds_bucket[1m])) >
labels: 0.25"
severity: warning for: 2m
annotations: labels:
summary: Etcd high number of failed proposals (instance {{ $labels.instance }}) severity: warning
description: "Etcd server got more than 5 failed proposals past hour\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" annotations:
summary: Etcd high commit durations (instance {{ $labels.instance }})
- alert: EtcdHighFsyncDurations description:
expr: 'histogram_quantile(0.99, rate(etcd_disk_wal_fsync_duration_seconds_bucket[1m])) > 0.5' "Etcd commit duration increasing, 99th percentile is over 0.25s\n VALUE = {{ $value
for: 2m }}\n LABELS = {{ $labels }}"
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 }}"
@@ -1,95 +1,123 @@
groups: 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 - alert: IstioMixerPrometheusDispatchesLow
expr: 'min(kube_deployment_status_replicas_available{deployment="istio-ingressgateway", namespace="istio-system"}) without (instance, pod) < 2' expr: 'sum(rate(mixer_runtime_dispatches_total{adapter=~"prometheus"}[1m])) < 180'
for: 1m for: 1m
labels: labels:
severity: warning severity: warning
annotations: annotations:
summary: Istio Kubernetes gateway availability drop (instance {{ $labels.instance }}) summary: Istio Mixer Prometheus dispatches low (instance {{ $labels.instance }})
description: "Gateway pods have dropped. Inbound traffic will likely be affected.\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" 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 - alert: IstioHighTotalRequestRate
expr: 'sum(rate(pilot_xds_push_errors[1m])) / sum(rate(pilot_xds_pushes[1m])) * 100 > 5' expr: 'sum(rate(istio_requests_total{reporter="destination"}[5m])) > 1000'
for: 1m for: 2m
labels: labels:
severity: warning severity: warning
annotations: annotations:
summary: Istio Pilot high total request rate (instance {{ $labels.instance }}) summary: Istio 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 }}" description:
"Global request rate in the service mesh is unusually high.\n VALUE = {{ $value
}}\n LABELS = {{ $labels }}"
- alert: IstioMixerPrometheusDispatchesLow - alert: IstioLowTotalRequestRate
expr: 'sum(rate(mixer_runtime_dispatches_total{adapter=~"prometheus"}[1m])) < 180' expr: 'sum(rate(istio_requests_total{reporter="destination"}[5m])) < 100'
for: 1m for: 2m
labels: labels:
severity: warning severity: warning
annotations: annotations:
summary: Istio Mixer Prometheus dispatches low (instance {{ $labels.instance }}) summary: Istio low total request rate (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 }}" description:
"Global request rate in the service mesh is unusually low.\n VALUE = {{ $value
}}\n LABELS = {{ $labels }}"
- alert: IstioHighTotalRequestRate - alert: IstioHigh4xxErrorRate
expr: 'sum(rate(istio_requests_total{reporter="destination"}[5m])) > 1000' expr:
for: 2m 'sum(rate(istio_requests_total{reporter="destination", response_code=~"4.*"}[5m])) /
labels: sum(rate(istio_requests_total{reporter="destination"}[5m])) * 100 > 5'
severity: warning for: 1m
annotations: labels:
summary: Istio high total request rate (instance {{ $labels.instance }}) severity: warning
description: "Global request rate in the service mesh is unusually high.\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" 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 - alert: IstioHigh5xxErrorRate
expr: 'sum(rate(istio_requests_total{reporter="destination"}[5m])) < 100' expr:
for: 2m 'sum(rate(istio_requests_total{reporter="destination", response_code=~"5.*"}[5m])) /
labels: sum(rate(istio_requests_total{reporter="destination"}[5m])) * 100 > 5'
severity: warning for: 1m
annotations: labels:
summary: Istio low total request rate (instance {{ $labels.instance }}) severity: warning
description: "Global request rate in the service mesh is unusually low.\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" 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 - alert: IstioHighRequestLatency
expr: 'sum(rate(istio_requests_total{reporter="destination", response_code=~"4.*"}[5m])) / sum(rate(istio_requests_total{reporter="destination"}[5m])) * 100 > 5' expr:
for: 1m 'rate(istio_request_duration_milliseconds_sum{reporter="destination"}[1m]) /
labels: rate(istio_request_duration_milliseconds_count{reporter="destination"}[1m]) > 100'
severity: warning for: 1m
annotations: labels:
summary: Istio high 4xx error rate (instance {{ $labels.instance }}) severity: warning
description: "High percentage of HTTP 5xx responses in Istio (> 5%).\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" 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 - alert: IstioLatency99Percentile
expr: 'sum(rate(istio_requests_total{reporter="destination", response_code=~"5.*"}[5m])) / sum(rate(istio_requests_total{reporter="destination"}[5m])) * 100 > 5' expr:
for: 1m "histogram_quantile(0.99, sum(rate(istio_request_duration_milliseconds_bucket[1m])) by
labels: (destination_canonical_service, destination_workload_namespace, source_canonical_service,
severity: warning source_workload_namespace, le)) > 1000"
annotations: for: 1m
summary: Istio high 5xx error rate (instance {{ $labels.instance }}) labels:
description: "High percentage of HTTP 5xx responses in Istio (> 5%).\n VALUE = {{ $value }}\n LABELS = {{ $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 - alert: IstioPilotDuplicateEntry
expr: 'rate(istio_request_duration_milliseconds_sum{reporter="destination"}[1m]) / rate(istio_request_duration_milliseconds_count{reporter="destination"}[1m]) > 100' expr: "sum(rate(pilot_duplicate_envoy_clusters{}[5m])) > 0"
for: 1m for: 0m
labels: labels:
severity: warning severity: critical
annotations: annotations:
summary: Istio high request latency (instance {{ $labels.instance }}) summary: Istio Pilot Duplicate Entry (instance {{ $labels.instance }})
description: "Istio average requests execution is longer than 100ms.\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" description:
"Istio pilot duplicate entry error.\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 }}"
@@ -1,311 +1,435 @@
groups: 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 - alert: KubernetesNodeDiskPressure
expr: 'kube_node_status_condition{condition="Ready",status="true"} == 0' expr: 'kube_node_status_condition{condition="DiskPressure",status="true"} == 1'
for: 10m for: 2m
labels: labels:
severity: critical severity: critical
annotations: annotations:
summary: Kubernetes Node ready (node {{ $labels.node }}) summary: Kubernetes disk pressure (node {{ $labels.node }})
description: "Node {{ $labels.node }} has been unready for a long time\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" description:
"Node {{ $labels.node }} has DiskPressure condition\n VALUE = {{ $value }}\n LABELS =
{{ $labels }}"
- alert: KubernetesNodeMemoryPressure - alert: KubernetesNodeNetworkUnavailable
expr: 'kube_node_status_condition{condition="MemoryPressure",status="true"} == 1' expr: 'kube_node_status_condition{condition="NetworkUnavailable",status="true"} == 1'
for: 2m for: 2m
labels: labels:
severity: critical severity: critical
annotations: annotations:
summary: Kubernetes memory pressure (node {{ $labels.node }}) summary: Kubernetes Node network unavailable (instance {{ $labels.instance }})
description: "Node {{ $labels.node }} has MemoryPressure condition\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" description:
"Node {{ $labels.node }} has NetworkUnavailable condition\n VALUE = {{ $value
}}\n LABELS = {{ $labels }}"
- alert: KubernetesNodeDiskPressure - alert: KubernetesNodeOutOfPodCapacity
expr: 'kube_node_status_condition{condition="DiskPressure",status="true"} == 1' expr:
for: 2m 'sum by (node) ((kube_pod_status_phase{phase="Running"} == 1) + on(uid) group_left(node)
labels: (0 * kube_pod_info{pod_template_hash=""})) / sum by (node)
severity: critical (kube_node_status_allocatable{resource="pods"}) * 100 > 90'
annotations: for: 2m
summary: Kubernetes disk pressure (node {{ $labels.node }}) labels:
description: "Node {{ $labels.node }} has DiskPressure condition\n VALUE = {{ $value }}\n LABELS = {{ $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 - alert: KubernetesContainerOomKiller
expr: 'kube_node_status_condition{condition="NetworkUnavailable",status="true"} == 1' expr:
for: 2m '(kube_pod_container_status_restarts_total - kube_pod_container_status_restarts_total
labels: offset 10m >= 1) and ignoring (reason)
severity: critical min_over_time(kube_pod_container_status_last_terminated_reason{reason="OOMKilled"}[10m])
annotations: == 1'
summary: Kubernetes Node network unavailable (instance {{ $labels.instance }}) for: 0m
description: "Node {{ $labels.node }} has NetworkUnavailable condition\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" 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 - alert: KubernetesJobFailed
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' expr: "kube_job_status_failed > 0"
for: 2m for: 0m
labels: labels:
severity: warning severity: warning
annotations: annotations:
summary: Kubernetes Node out of pod capacity (instance {{ $labels.instance }}) summary: Kubernetes Job failed ({{ $labels.namespace }}/{{ $labels.job_name }})
description: "Node {{ $labels.node }} is out of pod capacity\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" description:
"Job {{ $labels.namespace }}/{{ $labels.job_name }} failed to complete\n VALUE = {{
$value }}\n LABELS = {{ $labels }}"
- alert: KubernetesContainerOomKiller - alert: KubernetesCronjobSuspended
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' expr: "kube_cronjob_spec_suspend != 0"
for: 0m for: 0m
labels: labels:
severity: warning severity: warning
annotations: annotations:
summary: Kubernetes container oom killer ({{ $labels.namespace }}/{{ $labels.pod }}:{{ $labels.container }}) summary: Kubernetes CronJob suspended ({{ $labels.namespace }}/{{ $labels.cronjob }})
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 }}" description:
"CronJob {{ $labels.namespace }}/{{ $labels.cronjob }} is suspended\n VALUE = {{ $value
}}\n LABELS = {{ $labels }}"
- alert: KubernetesJobFailed - alert: KubernetesPersistentvolumeclaimPending
expr: 'kube_job_status_failed > 0' expr: 'kube_persistentvolumeclaim_status_phase{phase="Pending"} == 1'
for: 0m for: 2m
labels: labels:
severity: warning severity: warning
annotations: annotations:
summary: Kubernetes Job failed ({{ $labels.namespace }}/{{ $labels.job_name }}) summary:
description: "Job {{ $labels.namespace }}/{{ $labels.job_name }} failed to complete\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" Kubernetes PersistentVolumeClaim pending ({{ $labels.namespace }}/{{
$labels.persistentvolumeclaim }})
description:
"PersistentVolumeClaim {{ $labels.namespace }}/{{ $labels.persistentvolumeclaim }} is
pending\n VALUE = {{ $value }}\n LABELS = {{ $labels }}"
- alert: KubernetesCronjobSuspended - alert: KubernetesVolumeOutOfDiskSpace
expr: 'kube_cronjob_spec_suspend != 0' expr:
for: 0m "kubelet_volume_stats_available_bytes / kubelet_volume_stats_capacity_bytes * 100 < 10"
labels: for: 2m
severity: warning labels:
annotations: severity: warning
summary: Kubernetes CronJob suspended ({{ $labels.namespace }}/{{ $labels.cronjob }}) annotations:
description: "CronJob {{ $labels.namespace }}/{{ $labels.cronjob }} is suspended\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" 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 - alert: KubernetesVolumeFullInFourDays
expr: 'kube_persistentvolumeclaim_status_phase{phase="Pending"} == 1' expr: "predict_linear(kubelet_volume_stats_available_bytes[6h:5m], 4 * 24 * 3600) < 0"
for: 2m for: 0m
labels: labels:
severity: warning severity: critical
annotations: annotations:
summary: Kubernetes PersistentVolumeClaim pending ({{ $labels.namespace }}/{{ $labels.persistentvolumeclaim }}) summary: Kubernetes Volume full in four days (instance {{ $labels.instance }})
description: "PersistentVolumeClaim {{ $labels.namespace }}/{{ $labels.persistentvolumeclaim }} is pending\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" 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 - alert: KubernetesPersistentvolumeError
expr: 'kubelet_volume_stats_available_bytes / kubelet_volume_stats_capacity_bytes * 100 < 10' expr:
for: 2m 'kube_persistentvolume_status_phase{phase=~"Failed|Pending", job="kube-state-metrics"} > 0'
labels: for: 0m
severity: warning labels:
annotations: severity: critical
summary: Kubernetes Volume out of disk space (instance {{ $labels.instance }}) annotations:
description: "Volume is almost full (< 10% left)\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" 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 - alert: KubernetesStatefulsetDown
expr: 'predict_linear(kubelet_volume_stats_available_bytes[6h:5m], 4 * 24 * 3600) < 0' expr: "kube_statefulset_replicas != kube_statefulset_status_replicas_ready > 0"
for: 0m for: 1m
labels: labels:
severity: critical severity: critical
annotations: annotations:
summary: Kubernetes Volume full in four days (instance {{ $labels.instance }}) summary: Kubernetes StatefulSet down ({{ $labels.namespace }}/{{ $labels.statefulset }})
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 }}" description:
"StatefulSet {{ $labels.namespace }}/{{ $labels.statefulset }} went down\n VALUE = {{
$value }}\n LABELS = {{ $labels }}"
- alert: KubernetesPersistentvolumeError - alert: KubernetesHpaScaleInability
expr: 'kube_persistentvolume_status_phase{phase=~"Failed|Pending", job="kube-state-metrics"} > 0' expr:
for: 0m 'kube_horizontalpodautoscaler_status_condition{status="false", condition="AbleToScale"} ==
labels: 1'
severity: critical for: 2m
annotations: labels:
summary: Kubernetes PersistentVolumeClaim pending ({{ $labels.namespace }}/{{ $labels.persistentvolumeclaim }}) severity: warning
description: "Persistent volume {{ $labels.persistentvolume }} is in bad state\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" 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 - alert: KubernetesHpaMetricsUnavailability
expr: 'kube_statefulset_replicas != kube_statefulset_status_replicas_ready > 0' expr:
for: 1m 'kube_horizontalpodautoscaler_status_condition{status="false", condition="ScalingActive"}
labels: == 1'
severity: critical for: 0m
annotations: labels:
summary: Kubernetes StatefulSet down ({{ $labels.namespace }}/{{ $labels.statefulset }}) severity: warning
description: "StatefulSet {{ $labels.namespace }}/{{ $labels.statefulset }} went down\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" 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 - alert: KubernetesHpaScaleMaximum
expr: 'kube_horizontalpodautoscaler_status_condition{status="false", condition="AbleToScale"} == 1' expr:
for: 2m "kube_horizontalpodautoscaler_status_desired_replicas >=
labels: kube_horizontalpodautoscaler_spec_max_replicas"
severity: warning for: 2m
annotations: labels:
summary: Kubernetes HPA scale inability (instance {{ $labels.instance }}) severity: info
description: "HPA {{ $labels.namespace }}/{{ $labels.horizontalpodautoscaler }} is unable to scale\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" 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 - alert: KubernetesHpaUnderutilized
expr: 'kube_horizontalpodautoscaler_status_condition{status="false", condition="ScalingActive"} == 1' expr:
for: 0m "max(quantile_over_time(0.5, kube_horizontalpodautoscaler_status_desired_replicas[1d]) ==
labels: kube_horizontalpodautoscaler_spec_min_replicas) by (horizontalpodautoscaler) > 3"
severity: warning for: 0m
annotations: labels:
summary: Kubernetes HPA metrics unavailability (instance {{ $labels.instance }}) severity: info
description: "HPA {{ $labels.namespace }}/{{ $labels.horizontalpodautoscaler }} is unable to collect metrics\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" 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 - alert: KubernetesPodNotHealthy
expr: 'kube_horizontalpodautoscaler_status_desired_replicas >= kube_horizontalpodautoscaler_spec_max_replicas' expr: 'sum by (namespace, pod) (kube_pod_status_phase{phase=~"Pending|Unknown|Failed"}) > 0'
for: 2m for: 15m
labels: labels:
severity: info severity: critical
annotations: annotations:
summary: Kubernetes HPA scale maximum (instance {{ $labels.instance }}) summary: Kubernetes Pod not healthy ({{ $labels.namespace }}/{{ $labels.pod }})
description: "HPA {{ $labels.namespace }}/{{ $labels.horizontalpodautoscaler }} has hit maximum number of desired pods\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" 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 - alert: KubernetesPodCrashLooping
expr: 'max(quantile_over_time(0.5, kube_horizontalpodautoscaler_status_desired_replicas[1d]) == kube_horizontalpodautoscaler_spec_min_replicas) by (horizontalpodautoscaler) > 3' expr: "increase(kube_pod_container_status_restarts_total[1m]) > 3"
for: 0m for: 2m
labels: labels:
severity: info severity: warning
annotations: annotations:
summary: Kubernetes HPA underutilized (instance {{ $labels.instance }}) summary: Kubernetes pod crash looping ({{ $labels.namespace }}/{{ $labels.pod }})
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 }}" description:
"Pod {{ $labels.namespace }}/{{ $labels.pod }} is crash looping\n VALUE = {{ $value
}}\n LABELS = {{ $labels }}"
- alert: KubernetesPodNotHealthy - alert: KubernetesReplicasetReplicasMismatch
expr: 'sum by (namespace, pod) (kube_pod_status_phase{phase=~"Pending|Unknown|Failed"}) > 0' expr: "kube_replicaset_spec_replicas != kube_replicaset_status_ready_replicas"
for: 15m for: 10m
labels: labels:
severity: critical severity: warning
annotations: annotations:
summary: Kubernetes Pod not healthy ({{ $labels.namespace }}/{{ $labels.pod }}) summary:
description: "Pod {{ $labels.namespace }}/{{ $labels.pod }} has been in a non-running state for longer than 15 minutes.\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" Kubernetes ReplicasSet mismatch ({{ $labels.namespace }}/{{ $labels.replicaset }})
description:
"ReplicaSet {{ $labels.namespace }}/{{ $labels.replicaset }} replicas mismatch\n VALUE
= {{ $value }}\n LABELS = {{ $labels }}"
- alert: KubernetesPodCrashLooping - alert: KubernetesDeploymentReplicasMismatch
expr: 'increase(kube_pod_container_status_restarts_total[1m]) > 3' expr: "kube_deployment_spec_replicas != kube_deployment_status_replicas_available"
for: 2m for: 10m
labels: labels:
severity: warning severity: warning
annotations: annotations:
summary: Kubernetes pod crash looping ({{ $labels.namespace }}/{{ $labels.pod }}) summary:
description: "Pod {{ $labels.namespace }}/{{ $labels.pod }} is crash looping\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" Kubernetes Deployment replicas mismatch ({{ $labels.namespace }}/{{ $labels.deployment
}})
description:
"Deployment {{ $labels.namespace }}/{{ $labels.deployment }} replicas mismatch\n VALUE
= {{ $value }}\n LABELS = {{ $labels }}"
- alert: KubernetesReplicasetReplicasMismatch - alert: KubernetesStatefulsetReplicasMismatch
expr: 'kube_replicaset_spec_replicas != kube_replicaset_status_ready_replicas' expr: "kube_statefulset_status_replicas_ready != kube_statefulset_status_replicas"
for: 10m for: 10m
labels: labels:
severity: warning severity: warning
annotations: annotations:
summary: Kubernetes ReplicasSet mismatch ({{ $labels.namespace }}/{{ $labels.replicaset }}) summary: Kubernetes StatefulSet replicas mismatch (instance {{ $labels.instance }})
description: "ReplicaSet {{ $labels.namespace }}/{{ $labels.replicaset }} replicas mismatch\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" description:
"StatefulSet does not match the expected number of replicas.\n VALUE = {{ $value
}}\n LABELS = {{ $labels }}"
- alert: KubernetesDeploymentReplicasMismatch - alert: KubernetesDeploymentGenerationMismatch
expr: 'kube_deployment_spec_replicas != kube_deployment_status_replicas_available' expr: "kube_deployment_status_observed_generation != kube_deployment_metadata_generation"
for: 10m for: 10m
labels: labels:
severity: warning severity: critical
annotations: annotations:
summary: Kubernetes Deployment replicas mismatch ({{ $labels.namespace }}/{{ $labels.deployment }}) summary:
description: "Deployment {{ $labels.namespace }}/{{ $labels.deployment }} replicas mismatch\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" 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 - alert: KubernetesStatefulsetGenerationMismatch
expr: 'kube_statefulset_status_replicas_ready != kube_statefulset_status_replicas' expr: "kube_statefulset_status_observed_generation != kube_statefulset_metadata_generation"
for: 10m for: 10m
labels: labels:
severity: warning severity: critical
annotations: annotations:
summary: Kubernetes StatefulSet replicas mismatch (instance {{ $labels.instance }}) summary:
description: "StatefulSet does not match the expected number of replicas.\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" 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 - alert: KubernetesStatefulsetUpdateNotRolledOut
expr: 'kube_deployment_status_observed_generation != kube_deployment_metadata_generation' expr:
for: 10m "max without (revision) (kube_statefulset_status_current_revision unless
labels: kube_statefulset_status_update_revision) * (kube_statefulset_replicas !=
severity: critical kube_statefulset_status_replicas_updated)"
annotations: for: 10m
summary: Kubernetes Deployment generation mismatch ({{ $labels.namespace }}/{{ $labels.deployment }}) labels:
description: "Deployment {{ $labels.namespace }}/{{ $labels.deployment }} has failed but has not been rolled back.\n VALUE = {{ $value }}\n LABELS = {{ $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 - alert: KubernetesDaemonsetRolloutStuck
expr: 'kube_statefulset_status_observed_generation != kube_statefulset_metadata_generation' expr:
for: 10m "kube_daemonset_status_number_ready / kube_daemonset_status_desired_number_scheduled * 100
labels: < 100 or kube_daemonset_status_desired_number_scheduled -
severity: critical kube_daemonset_status_current_number_scheduled > 0"
annotations: for: 10m
summary: Kubernetes StatefulSet generation mismatch ({{ $labels.namespace }}/{{ $labels.statefulset }}) labels:
description: "StatefulSet {{ $labels.namespace }}/{{ $labels.statefulset }} has failed but has not been rolled back.\n VALUE = {{ $value }}\n LABELS = {{ $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 - alert: KubernetesDaemonsetMisscheduled
expr: 'max without (revision) (kube_statefulset_status_current_revision unless kube_statefulset_status_update_revision) * (kube_statefulset_replicas != kube_statefulset_status_replicas_updated)' expr: "kube_daemonset_status_number_misscheduled > 0"
for: 10m for: 1m
labels: labels:
severity: warning severity: critical
annotations: annotations:
summary: Kubernetes StatefulSet update not rolled out ({{ $labels.namespace }}/{{ $labels.statefulset }}) summary:
description: "StatefulSet {{ $labels.namespace }}/{{ $labels.statefulset }} update has not been rolled out.\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" 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 - alert: KubernetesCronjobTooLong
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' expr: "time() - kube_cronjob_next_schedule_time > 3600"
for: 10m for: 0m
labels: labels:
severity: warning severity: warning
annotations: annotations:
summary: Kubernetes DaemonSet rollout stuck ({{ $labels.namespace }}/{{ $labels.daemonset }}) summary: Kubernetes CronJob too long ({{ $labels.namespace }}/{{ $labels.cronjob }})
description: "Some Pods of DaemonSet {{ $labels.namespace }}/{{ $labels.daemonset }} are not scheduled or not ready\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" description:
"CronJob {{ $labels.namespace }}/{{ $labels.cronjob }} is taking more than 1h to
complete.\n VALUE = {{ $value }}\n LABELS = {{ $labels }}"
- alert: KubernetesDaemonsetMisscheduled - alert: KubernetesJobSlowCompletion
expr: 'kube_daemonset_status_number_misscheduled > 0' expr: "kube_job_spec_completions - kube_job_status_succeeded - kube_job_status_failed > 0"
for: 1m for: 12h
labels: labels:
severity: critical severity: critical
annotations: annotations:
summary: Kubernetes DaemonSet misscheduled ({{ $labels.namespace }}/{{ $labels.daemonset }}) summary: Kubernetes job slow completion ({{ $labels.namespace }}/{{ $labels.job_name }})
description: "Some Pods of DaemonSet {{ $labels.namespace }}/{{ $labels.daemonset }} are running where they are not supposed to run\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" description:
"Kubernetes Job {{ $labels.namespace }}/{{ $labels.job_name }} did not complete in
time.\n VALUE = {{ $value }}\n LABELS = {{ $labels }}"
- alert: KubernetesCronjobTooLong - alert: KubernetesApiServerErrors
expr: 'time() - kube_cronjob_next_schedule_time > 3600' expr:
for: 0m 'sum(rate(apiserver_request_total{job="apiserver",code=~"^(?:5..)$"}[1m])) /
labels: sum(rate(apiserver_request_total{job="apiserver"}[1m])) * 100 > 3'
severity: warning for: 2m
annotations: labels:
summary: Kubernetes CronJob too long ({{ $labels.namespace }}/{{ $labels.cronjob }}) severity: critical
description: "CronJob {{ $labels.namespace }}/{{ $labels.cronjob }} is taking more than 1h to complete.\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" 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 - alert: KubernetesApiClientErrors
expr: 'kube_job_spec_completions - kube_job_status_succeeded - kube_job_status_failed > 0' expr:
for: 12h '(sum(rate(rest_client_requests_total{code=~"(4|5).."}[1m])) by (instance, job) /
labels: sum(rate(rest_client_requests_total[1m])) by (instance, job)) * 100 > 1'
severity: critical for: 2m
annotations: labels:
summary: Kubernetes job slow completion ({{ $labels.namespace }}/{{ $labels.job_name }}) severity: critical
description: "Kubernetes Job {{ $labels.namespace }}/{{ $labels.job_name }} did not complete in time.\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" 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 - alert: KubernetesClientCertificateExpiresNextWeek
expr: 'sum(rate(apiserver_request_total{job="apiserver",code=~"^(?:5..)$"}[1m])) / sum(rate(apiserver_request_total{job="apiserver"}[1m])) * 100 > 3' expr:
for: 2m 'apiserver_client_certificate_expiration_seconds_count{job="apiserver"} > 0 and
labels: histogram_quantile(0.01, sum by (job, le)
severity: critical (rate(apiserver_client_certificate_expiration_seconds_bucket{job="apiserver"}[5m]))) <
annotations: 7*24*60*60'
summary: Kubernetes API server errors (instance {{ $labels.instance }}) for: 0m
description: "Kubernetes API server is experiencing high error rate\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" 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 - alert: KubernetesClientCertificateExpiresSoon
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' expr:
for: 2m 'apiserver_client_certificate_expiration_seconds_count{job="apiserver"} > 0 and
labels: histogram_quantile(0.01, sum by (job, le)
severity: critical (rate(apiserver_client_certificate_expiration_seconds_bucket{job="apiserver"}[5m]))) <
annotations: 24*60*60'
summary: Kubernetes API client errors (instance {{ $labels.instance }}) for: 0m
description: "Kubernetes API client is experiencing high error rate\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" 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 - alert: KubernetesApiServerLatency
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' expr:
for: 0m 'histogram_quantile(0.99,
labels: sum(rate(apiserver_request_duration_seconds_bucket{subresource!="log",verb!~"^(?:CONNECT|WATCHLIST|WATCH|PROXY)$"}
severity: warning [10m])) WITHOUT (instance, resource)) > 1'
annotations: for: 2m
summary: Kubernetes client certificate expires next week (instance {{ $labels.instance }}) labels:
description: "A client certificate used to authenticate to the apiserver is expiring next week.\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" severity: warning
annotations:
- alert: KubernetesClientCertificateExpiresSoon summary: Kubernetes API server latency (instance {{ $labels.instance }})
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' description:
for: 0m "Kubernetes API server has a 99th percentile latency of {{ $value }} seconds for {{
labels: $labels.verb }} {{ $labels.resource }}.\n VALUE = {{ $value }}\n LABELS = {{ $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 }}"
@@ -1,347 +1,508 @@
groups: 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 - alert: HostMemoryIsUnderutilized
expr: '(node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes * 100 < 10) * on(instance) group_left (nodename) node_uname_info{nodename=~".+"}' expr:
for: 2m '(100 - (avg_over_time(node_memory_MemAvailable_bytes[30m]) / node_memory_MemTotal_bytes *
labels: 100) < 20) * on(instance) group_left (nodename) node_uname_info{nodename=~".+"}'
severity: warning for: 1w
annotations: labels:
summary: Host out of memory (instance {{ $labels.instance }}) severity: info
description: "Node memory is filling up (< 10% left)\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" 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 - alert: HostUnusualNetworkThroughputIn
expr: '(rate(node_vmstat_pgmajfault[1m]) > 1000) * on(instance) group_left (nodename) node_uname_info{nodename=~".+"}' expr:
for: 2m '(sum by (instance) (rate(node_network_receive_bytes_total[2m])) / 1024 / 1024 > 100) *
labels: on(instance) group_left (nodename) node_uname_info{nodename=~".+"}'
severity: warning for: 5m
annotations: labels:
summary: Host memory under memory pressure (instance {{ $labels.instance }}) severity: warning
description: "The node is under heavy memory pressure. High rate of major page faults\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" 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 - alert: HostUnusualNetworkThroughputOut
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=~".+"}' expr:
for: 1w '(sum by (instance) (rate(node_network_transmit_bytes_total[2m])) / 1024 / 1024 > 100) *
labels: on(instance) group_left (nodename) node_uname_info{nodename=~".+"}'
severity: info for: 5m
annotations: labels:
summary: Host Memory is underutilized (instance {{ $labels.instance }}) severity: warning
description: "Node memory is < 20% for 1 week. Consider reducing memory space. (instance {{ $labels.instance }})\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" 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 - alert: HostUnusualDiskReadRate
expr: '(sum by (instance) (rate(node_network_receive_bytes_total[2m])) / 1024 / 1024 > 100) * on(instance) group_left (nodename) node_uname_info{nodename=~".+"}' expr:
for: 5m '(sum by (instance) (rate(node_disk_read_bytes_total[2m])) / 1024 / 1024 > 50) *
labels: on(instance) group_left (nodename) node_uname_info{nodename=~".+"}'
severity: warning for: 5m
annotations: labels:
summary: Host unusual network throughput in (instance {{ $labels.instance }}) severity: warning
description: "Host network interfaces are probably receiving too much data (> 100 MB/s)\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" 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 - alert: HostUnusualDiskWriteRate
expr: '(sum by (instance) (rate(node_network_transmit_bytes_total[2m])) / 1024 / 1024 > 100) * on(instance) group_left (nodename) node_uname_info{nodename=~".+"}' expr:
for: 5m '(sum by (instance) (rate(node_disk_written_bytes_total[2m])) / 1024 / 1024 > 50) *
labels: on(instance) group_left (nodename) node_uname_info{nodename=~".+"}'
severity: warning for: 2m
annotations: labels:
summary: Host unusual network throughput out (instance {{ $labels.instance }}) severity: warning
description: "Host network interfaces are probably sending too much data (> 100 MB/s)\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" 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 - alert: HostOutOfDiskSpace
expr: '(sum by (instance) (rate(node_disk_read_bytes_total[2m])) / 1024 / 1024 > 50) * on(instance) group_left (nodename) node_uname_info{nodename=~".+"}' expr:
for: 5m '((node_filesystem_avail_bytes * 100) / node_filesystem_size_bytes < 10 and ON (instance,
labels: device, mountpoint) node_filesystem_readonly == 0) * on(instance) group_left (nodename)
severity: warning node_uname_info{nodename=~".+"}'
annotations: for: 2m
summary: Host unusual disk read rate (instance {{ $labels.instance }}) labels:
description: "Disk is probably reading too much data (> 50 MB/s)\n VALUE = {{ $value }}\n LABELS = {{ $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 - alert: HostDiskWillFillIn24Hours
expr: '(sum by (instance) (rate(node_disk_written_bytes_total[2m])) / 1024 / 1024 > 50) * on(instance) group_left (nodename) node_uname_info{nodename=~".+"}' expr:
for: 2m '((node_filesystem_avail_bytes * 100) / node_filesystem_size_bytes < 10 and ON (instance,
labels: device, mountpoint) predict_linear(node_filesystem_avail_bytes{fstype!~"tmpfs"}[1h], 24 *
severity: warning 3600) < 0 and ON (instance, device, mountpoint) node_filesystem_readonly == 0) *
annotations: on(instance) group_left (nodename) node_uname_info{nodename=~".+"}'
summary: Host unusual disk write rate (instance {{ $labels.instance }}) for: 2m
description: "Disk is probably writing too much data (> 50 MB/s)\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" 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 - alert: HostOutOfInodes
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=~".+"}' expr:
for: 2m '(node_filesystem_files_free{fstype!="msdosfs"} / node_filesystem_files{fstype!="msdosfs"}
labels: * 100 < 10 and ON (instance, device, mountpoint) node_filesystem_readonly == 0) *
severity: warning on(instance) group_left (nodename) node_uname_info{nodename=~".+"}'
annotations: for: 2m
summary: Host out of disk space (instance {{ $labels.instance }}) labels:
description: "Disk is almost full (< 10% left)\n VALUE = {{ $value }}\n LABELS = {{ $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 - alert: HostFilesystemDeviceError
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=~".+"}' expr: "node_filesystem_device_error == 1"
for: 2m for: 0m
labels: labels:
severity: warning severity: critical
annotations: annotations:
summary: Host disk will fill in 24 hours (instance {{ $labels.instance }}) summary: Host filesystem device error (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 }}" description:
"{{ $labels.instance }}: Device error with the {{ $labels.mountpoint }}
filesystem\n VALUE = {{ $value }}\n LABELS = {{ $labels }}"
- alert: HostOutOfInodes - alert: HostInodesWillFillIn24Hours
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=~".+"}' expr:
for: 2m '(node_filesystem_files_free{fstype!="msdosfs"} / node_filesystem_files{fstype!="msdosfs"}
labels: * 100 < 10 and predict_linear(node_filesystem_files_free{fstype!="msdosfs"}[1h], 24 *
severity: warning 3600) < 0 and ON (instance, device, mountpoint)
annotations: node_filesystem_readonly{fstype!="msdosfs"} == 0) * on(instance) group_left (nodename)
summary: Host out of inodes (instance {{ $labels.instance }}) node_uname_info{nodename=~".+"}'
description: "Disk is almost running out of available inodes (< 10% left)\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" 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 - alert: HostUnusualDiskReadLatency
expr: 'node_filesystem_device_error == 1' expr:
for: 0m '(rate(node_disk_read_time_seconds_total[1m]) / rate(node_disk_reads_completed_total[1m])
labels: > 0.1 and rate(node_disk_reads_completed_total[1m]) > 0) * on(instance) group_left
severity: critical (nodename) node_uname_info{nodename=~".+"}'
annotations: for: 2m
summary: Host filesystem device error (instance {{ $labels.instance }}) labels:
description: "{{ $labels.instance }}: Device error with the {{ $labels.mountpoint }} filesystem\n VALUE = {{ $value }}\n LABELS = {{ $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 - alert: HostUnusualDiskWriteLatency
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=~".+"}' expr:
for: 2m '(rate(node_disk_write_time_seconds_total[1m]) /
labels: rate(node_disk_writes_completed_total[1m]) > 0.1 and
severity: warning rate(node_disk_writes_completed_total[1m]) > 0) * on(instance) group_left (nodename)
annotations: node_uname_info{nodename=~".+"}'
summary: Host inodes will fill in 24 hours (instance {{ $labels.instance }}) for: 2m
description: "Filesystem is predicted to run out of inodes within the next 24 hours at current write rate\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" 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 - alert: HostHighCpuLoad
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=~".+"}' expr:
for: 2m '(sum by (instance) (avg by (mode, instance)
labels: (rate(node_cpu_seconds_total{mode!="idle"}[2m]))) > 0.8) * on(instance) group_left
severity: warning (nodename) node_uname_info{nodename=~".+"}'
annotations: for: 10m
summary: Host unusual disk read latency (instance {{ $labels.instance }}) labels:
description: "Disk latency is growing (read operations > 100ms)\n VALUE = {{ $value }}\n LABELS = {{ $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 - alert: HostCpuIsUnderutilized
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=~".+"}' expr:
for: 2m '(100 - (rate(node_cpu_seconds_total{mode="idle"}[30m]) * 100) < 20) * on(instance)
labels: group_left (nodename) node_uname_info{nodename=~".+"}'
severity: warning for: 1w
annotations: labels:
summary: Host unusual disk write latency (instance {{ $labels.instance }}) severity: info
description: "Disk latency is growing (write operations > 100ms)\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" 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 - alert: HostCpuStealNoisyNeighbor
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=~".+"}' expr:
for: 10m '(avg by(instance) (rate(node_cpu_seconds_total{mode="steal"}[5m])) * 100 > 10) *
labels: on(instance) group_left (nodename) node_uname_info{nodename=~".+"}'
severity: warning for: 0m
annotations: labels:
summary: Host high CPU load (instance {{ $labels.instance }}) severity: warning
description: "CPU load is > 80%\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" 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 - alert: HostCpuHighIowait
expr: '(100 - (rate(node_cpu_seconds_total{mode="idle"}[30m]) * 100) < 20) * on(instance) group_left (nodename) node_uname_info{nodename=~".+"}' expr:
for: 1w '(avg by (instance) (rate(node_cpu_seconds_total{mode="iowait"}[5m])) * 100 > 10) *
labels: on(instance) group_left (nodename) node_uname_info{nodename=~".+"}'
severity: info for: 0m
annotations: labels:
summary: Host CPU is underutilized (instance {{ $labels.instance }}) severity: warning
description: "CPU load is < 20% for 1 week. Consider reducing the number of CPUs.\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" 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 - alert: HostUnusualDiskIo
expr: '(avg by(instance) (rate(node_cpu_seconds_total{mode="steal"}[5m])) * 100 > 10) * on(instance) group_left (nodename) node_uname_info{nodename=~".+"}' expr:
for: 0m '(rate(node_disk_io_time_seconds_total[1m]) > 0.5) * on(instance) group_left (nodename)
labels: node_uname_info{nodename=~".+"}'
severity: warning for: 5m
annotations: labels:
summary: Host CPU steal noisy neighbor (instance {{ $labels.instance }}) severity: warning
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 }}" 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 - alert: HostContextSwitching
expr: '(avg by (instance) (rate(node_cpu_seconds_total{mode="iowait"}[5m])) * 100 > 10) * on(instance) group_left (nodename) node_uname_info{nodename=~".+"}' expr:
for: 0m '((rate(node_context_switches_total[5m])) / (count without(cpu, mode)
labels: (node_cpu_seconds_total{mode="idle"})) > 10000) * on(instance) group_left (nodename)
severity: warning node_uname_info{nodename=~".+"}'
annotations: for: 0m
summary: Host CPU high iowait (instance {{ $labels.instance }}) labels:
description: "CPU iowait > 10%. A high iowait means that you are disk or network bound.\n VALUE = {{ $value }}\n LABELS = {{ $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 - alert: HostSwapIsFillingUp
expr: '(rate(node_disk_io_time_seconds_total[1m]) > 0.5) * on(instance) group_left (nodename) node_uname_info{nodename=~".+"}' expr:
for: 5m '((1 - (node_memory_SwapFree_bytes / node_memory_SwapTotal_bytes)) * 100 > 80) *
labels: on(instance) group_left (nodename) node_uname_info{nodename=~".+"}'
severity: warning for: 2m
annotations: labels:
summary: Host unusual disk IO (instance {{ $labels.instance }}) severity: warning
description: "Time spent in IO is too high on {{ $labels.instance }}. Check storage for issues.\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" annotations:
summary: Host swap is filling up (instance {{ $labels.instance }})
description: "Swap is filling up (>80%)\n VALUE = {{ $value }}\n LABELS = {{ $labels }}"
- alert: HostContextSwitching - alert: HostSystemdServiceCrashed
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=~".+"}' expr:
for: 0m '(node_systemd_unit_state{state="failed"} == 1) * on(instance) group_left (nodename)
labels: node_uname_info{nodename=~".+"}'
severity: warning for: 0m
annotations: labels:
summary: Host context switching (instance {{ $labels.instance }}) severity: warning
description: "Context switching is growing on the node (> 10000 / CPU / s)\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" annotations:
summary: Host systemd service crashed (instance {{ $labels.instance }})
description: "systemd service crashed\n VALUE = {{ $value }}\n LABELS = {{ $labels }}"
- alert: HostSwapIsFillingUp - alert: HostPhysicalComponentTooHot
expr: '((1 - (node_memory_SwapFree_bytes / node_memory_SwapTotal_bytes)) * 100 > 80) * on(instance) group_left (nodename) node_uname_info{nodename=~".+"}' expr:
for: 2m '((node_hwmon_temp_celsius * ignoring(label) group_left(instance, job, node, sensor)
labels: node_hwmon_sensor_label{label!="tctl"} > 75)) * on(instance) group_left (nodename)
severity: warning node_uname_info{nodename=~".+"}'
annotations: for: 5m
summary: Host swap is filling up (instance {{ $labels.instance }}) labels:
description: "Swap is filling up (>80%)\n VALUE = {{ $value }}\n LABELS = {{ $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 - alert: HostNodeOvertemperatureAlarm
expr: '(node_systemd_unit_state{state="failed"} == 1) * on(instance) group_left (nodename) node_uname_info{nodename=~".+"}' expr:
for: 0m '(node_hwmon_temp_crit_alarm_celsius == 1) * on(instance) group_left (nodename)
labels: node_uname_info{nodename=~".+"}'
severity: warning for: 0m
annotations: labels:
summary: Host systemd service crashed (instance {{ $labels.instance }}) severity: critical
description: "systemd service crashed\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" annotations:
summary: Host node overtemperature alarm (instance {{ $labels.instance }})
description:
"Physical node temperature alarm triggered\n VALUE = {{ $value }}\n LABELS = {{
$labels }}"
- alert: HostPhysicalComponentTooHot - alert: HostRaidArrayGotInactive
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=~".+"}' expr:
for: 5m '(node_md_state{state="inactive"} > 0) * on(instance) group_left (nodename)
labels: node_uname_info{nodename=~".+"}'
severity: warning for: 0m
annotations: labels:
summary: Host physical component too hot (instance {{ $labels.instance }}) severity: critical
description: "Physical hardware component too hot\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" 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 - alert: HostRaidDiskFailure
expr: '(node_hwmon_temp_crit_alarm_celsius == 1) * on(instance) group_left (nodename) node_uname_info{nodename=~".+"}' expr:
for: 0m '(node_md_disks{state="failed"} > 0) * on(instance) group_left (nodename)
labels: node_uname_info{nodename=~".+"}'
severity: critical for: 2m
annotations: labels:
summary: Host node overtemperature alarm (instance {{ $labels.instance }}) severity: warning
description: "Physical node temperature alarm triggered\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" 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 - alert: HostKernelVersionDeviations
expr: '(node_md_state{state="inactive"} > 0) * on(instance) group_left (nodename) node_uname_info{nodename=~".+"}' expr:
for: 0m '(count(sum(label_replace(node_uname_info, "kernel", "$1", "release",
labels: "([0-9]+.[0-9]+.[0-9]+).*")) by (kernel)) > 1) * on(instance) group_left (nodename)
severity: critical node_uname_info{nodename=~".+"}'
annotations: for: 6h
summary: Host RAID array got inactive (instance {{ $labels.instance }}) labels:
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 }}" 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 - alert: HostOomKillDetected
expr: '(node_md_disks{state="failed"} > 0) * on(instance) group_left (nodename) node_uname_info{nodename=~".+"}' expr:
for: 2m '(increase(node_vmstat_oom_kill[1m]) > 0) * on(instance) group_left (nodename)
labels: node_uname_info{nodename=~".+"}'
severity: warning for: 0m
annotations: labels:
summary: Host RAID disk failure (instance {{ $labels.instance }}) severity: warning
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 }}" annotations:
summary: Host OOM kill detected (instance {{ $labels.instance }})
description: "OOM kill detected\n VALUE = {{ $value }}\n LABELS = {{ $labels }}"
- alert: HostKernelVersionDeviations - alert: HostEdacCorrectableErrorsDetected
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=~".+"}' expr:
for: 6h '(increase(node_edac_correctable_errors_total[1m]) > 0) * on(instance) group_left
labels: (nodename) node_uname_info{nodename=~".+"}'
severity: warning for: 0m
annotations: labels:
summary: Host kernel version deviations (instance {{ $labels.instance }}) severity: info
description: "Different kernel versions are running\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" 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 - alert: HostEdacUncorrectableErrorsDetected
expr: '(increase(node_vmstat_oom_kill[1m]) > 0) * on(instance) group_left (nodename) node_uname_info{nodename=~".+"}' expr:
for: 0m '(node_edac_uncorrectable_errors_total > 0) * on(instance) group_left (nodename)
labels: node_uname_info{nodename=~".+"}'
severity: warning for: 0m
annotations: labels:
summary: Host OOM kill detected (instance {{ $labels.instance }}) severity: warning
description: "OOM kill detected\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" 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 - alert: HostNetworkReceiveErrors
expr: '(increase(node_edac_correctable_errors_total[1m]) > 0) * on(instance) group_left (nodename) node_uname_info{nodename=~".+"}' expr:
for: 0m '(rate(node_network_receive_errs_total[2m]) / rate(node_network_receive_packets_total[2m])
labels: > 0.01) * on(instance) group_left (nodename) node_uname_info{nodename=~".+"}'
severity: info for: 2m
annotations: labels:
summary: Host EDAC Correctable Errors detected (instance {{ $labels.instance }}) severity: warning
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 }}" 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 - alert: HostNetworkTransmitErrors
expr: '(node_edac_uncorrectable_errors_total > 0) * on(instance) group_left (nodename) node_uname_info{nodename=~".+"}' expr:
for: 0m '(rate(node_network_transmit_errs_total[2m]) /
labels: rate(node_network_transmit_packets_total[2m]) > 0.01) * on(instance) group_left (nodename)
severity: warning node_uname_info{nodename=~".+"}'
annotations: for: 2m
summary: Host EDAC Uncorrectable Errors detected (instance {{ $labels.instance }}) labels:
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 }}" 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 - alert: HostNetworkInterfaceSaturated
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=~".+"}' expr:
for: 2m '((rate(node_network_receive_bytes_total{device!~"^tap.*|^vnet.*|^veth.*|^tun.*"}[1m]) +
labels: rate(node_network_transmit_bytes_total{device!~"^tap.*|^vnet.*|^veth.*|^tun.*"}[1m])) /
severity: warning node_network_speed_bytes{device!~"^tap.*|^vnet.*|^veth.*|^tun.*"} > 0.8 < 10000) *
annotations: on(instance) group_left (nodename) node_uname_info{nodename=~".+"}'
summary: Host Network Receive Errors (instance {{ $labels.instance }}) for: 1m
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 }}" 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 - alert: HostNetworkBondDegraded
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=~".+"}' expr:
for: 2m '((node_bonding_active - node_bonding_slaves) != 0) * on(instance) group_left (nodename)
labels: node_uname_info{nodename=~".+"}'
severity: warning for: 2m
annotations: labels:
summary: Host Network Transmit Errors (instance {{ $labels.instance }}) severity: warning
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 }}" 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 - alert: HostConntrackLimit
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=~".+"}' expr:
for: 1m '(node_nf_conntrack_entries / node_nf_conntrack_entries_limit > 0.8) * on(instance)
labels: group_left (nodename) node_uname_info{nodename=~".+"}'
severity: warning for: 5m
annotations: labels:
summary: Host Network Interface Saturated (instance {{ $labels.instance }}) severity: warning
description: "The network interface \"{{ $labels.device }}\" on \"{{ $labels.instance }}\" is getting overloaded.\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" annotations:
summary: Host conntrack limit (instance {{ $labels.instance }})
description:
"The number of conntrack is approaching limit\n VALUE = {{ $value }}\n LABELS = {{
$labels }}"
- alert: HostNetworkBondDegraded - alert: HostClockSkew
expr: '((node_bonding_active - node_bonding_slaves) != 0) * on(instance) group_left (nodename) node_uname_info{nodename=~".+"}' expr:
for: 2m '((node_timex_offset_seconds > 0.05 and deriv(node_timex_offset_seconds[5m]) >= 0) or
labels: (node_timex_offset_seconds < -0.05 and deriv(node_timex_offset_seconds[5m]) <= 0)) *
severity: warning on(instance) group_left (nodename) node_uname_info{nodename=~".+"}'
annotations: for: 10m
summary: Host Network Bond Degraded (instance {{ $labels.instance }}) labels:
description: "Bond \"{{ $labels.device }}\" degraded on \"{{ $labels.instance }}\".\n VALUE = {{ $value }}\n LABELS = {{ $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 - alert: HostClockNotSynchronising
expr: '(node_nf_conntrack_entries / node_nf_conntrack_entries_limit > 0.8) * on(instance) group_left (nodename) node_uname_info{nodename=~".+"}' expr:
for: 5m '(min_over_time(node_timex_sync_status[1m]) == 0 and node_timex_maxerror_seconds >= 16) *
labels: on(instance) group_left (nodename) node_uname_info{nodename=~".+"}'
severity: warning for: 2m
annotations: labels:
summary: Host conntrack limit (instance {{ $labels.instance }}) severity: warning
description: "The number of conntrack is approaching limit\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" 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 - alert: HostRequiresReboot
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=~".+"}' expr:
for: 10m '(node_reboot_required > 0) * on(instance) group_left (nodename)
labels: node_uname_info{nodename=~".+"}'
severity: warning for: 4h
annotations: labels:
summary: Host clock skew (instance {{ $labels.instance }}) severity: info
description: "Clock skew detected. Clock is out of sync. Ensure NTP is configured correctly on this host.\n VALUE = {{ $value }}\n LABELS = {{ $labels }}" annotations:
summary: Host requires reboot (instance {{ $labels.instance }})
- alert: HostClockNotSynchronising description:
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=~".+"}' "{{ $labels.instance }} requires a reboot.\n VALUE = {{ $value }}\n LABELS = {{
for: 2m $labels }}"
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 }}"
+10 -7
View File
@@ -4,7 +4,8 @@
I'm running two Kubernetes clusters, one for production and one for testing. 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 ## 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-1`
1. `k3s-prod-1-master-2` 1. `k3s-prod-1-master-2`
1. `k3s-prod-1-master-3` 1. `k3s-prod-1-master-3`
2. `k3s-prod-1-worker-1` 1. `k3s-prod-1-worker-1`
2. `k3s-prod-1-worker-2` 1. `k3s-prod-1-worker-2`
2. `k3s-prod-1-worker-3` 1. `k3s-prod-1-worker-3`
1. For testing:. 1. For testing:.
1. `k3s-test-1-master-1` 1. `k3s-test-1-master-1`
2. `k3s-test-1-worker-1` 2. `k3s-test-1-worker-1`
3. `k3s-test-1-worker-2` 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 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/ [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
-2
View File
@@ -29,5 +29,3 @@ K3S_TOKEN_FILE=./kubevirt-k3s-token
USB_PATH=/run/media/ryan/NIXOS_K3S USB_PATH=/run/media/ryan/NIXOS_K3S
cp $K3S_TOKEN_FILE $USB_PATH cp $K3S_TOKEN_FILE $USB_PATH
``` ```
+9 -5
View File
@@ -1,9 +1,13 @@
# Library # 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. `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. `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. `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. `colmenaSystem.nix`: A function that generate config(another function) for remote deployment
1. `default.nix`: import all the above functions, and some custom useful functions, and export them as a single attribute set. 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
View File
@@ -3,4 +3,3 @@
1. `darwin`: macOS-specific configuration. 1. `darwin`: macOS-specific configuration.
2. `nixos`: NixOS-specific configuration. 2. `nixos`: NixOS-specific configuration.
3. `base.nix`: Common configuration for both NixOS and Nix-Darwin. 3. `base.nix`: Common configuration for both NixOS and Nix-Darwin.
+2 -1
View File
@@ -2,4 +2,5 @@
This directory contains the modules for [Nix-Darwin](https://github.com/LnL7/nix-darwin). 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.
+10 -7
View File
@@ -1,10 +1,13 @@
# Remote Desktop # 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) 2. **Wayland**: (not tested)
1. `waypipe`: similar to `ssh -X`, transfer wayland data over a ssh connection. 3. `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. 4. [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/> 5. confirmed broken currently:
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. <https://www.reddit.com/r/rustdesk/comments/1912373/rustdesk_on_hyprland/>
1. broken currently: <https://github.com/LizardByte/Sunshine/pull/1977> 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>
+35 -25
View File
@@ -1,12 +1,16 @@
# Nix Environment Setup for Host: Idols - Ai # 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: 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: TODOs:
@@ -14,11 +18,13 @@ TODOs:
## Why an extra flake is needed? ## 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. The configuration of the main flake, [/flake.nix](/flake.nix), is heavy, and it takes time to debug
This simplified flake is tiny and can be deployed very quickly, it helps me to: & 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. 1. Adjust & verify my `hardware-configuration.nix` modification quickly before deploying the main
2. Test some new filesystem related features on a NixOS virtual machine, such as impermanence, Secure Boot, TPM2, Encryption, etc. 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 ## 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) > [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. Securing a root file system is where dm-crypt excels, feature and performance-wise. An encrypted
An encrypted root file system protects everything on the system, it make the system a black box to the attacker. 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. 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. 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: 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 parted /dev/nvme0n1 -- set 1 esp on # part-1
# Create the root partition using the rest of the disk # Create the root partition using the rest of the disk
# Format: # Format:
# mkpart [part-type name fs-type] start end # mkpart [part-type name fs-type] start end
parted /dev/nvme0n1 -- mkpart primary 630MB 100% # part-1 parted /dev/nvme0n1 -- mkpart primary 630MB 100% # part-1
@@ -80,7 +87,7 @@ Encrypting the root partition:
```bash ```bash
lsblk lsblk
# show cryptsetup's compiled in defualts # show cryptsetup's compiled in defaults
cryptsetup --help cryptsetup --help
# NOTE: `cat shoukei.md | grep luks > luks.sh` to generate this script # 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 cryptsetup luksDump /dev/nvme0n1p2
# open(unlock) the device with the passphrase you just set # 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 # show disk status
lsblk lsblk
@@ -103,7 +110,7 @@ Formatting the root partition:
# NOTE: `cat shoukei.md | grep create-btrfs > btrfs.sh` to generate this script # NOTE: `cat shoukei.md | grep create-btrfs > btrfs.sh` to generate this script
mkfs.fat -F 32 -n ESP /dev/nvme0n1p1 # create-btrfs mkfs.fat -F 32 -n ESP /dev/nvme0n1p1 # create-btrfs
# format the root partition with btrfs and label it # 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 the root partition and create subvolumes
mount /dev/mapper/crypted-nixos /mnt # create-btrfs 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 # NOTE: `cat shoukei.md | grep mount-1 > mount-1.sh` to generate this script
# Remount the root partition with the subvolumes you just created # Remount the root partition with the subvolumes you just created
# #
# Enable zstd compression to: # Enable zstd compression to:
# 1. Reduce the read/write operations, which helps to: # 1. Reduce the read/write operations, which helps to:
# 1. Extend the life of the SSD. # 1. Extend the life of the SSD.
@@ -152,10 +159,10 @@ Now, the disk status should be:
```bash ```bash
# show disk status # show disk status
$ lsblk $ 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 ├─nvme0n1p1 259:2 0 600M 0 part /mnt/boot
└─nvme0n1p2 259:3 0 1.8T 0 part └─nvme0n1p2 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/persistent
/mnt/snapshots /mnt/snapshots
/mnt/nix /mnt/nix
@@ -243,10 +250,10 @@ reboot
And then reboot. And then reboot.
## Deploying the main flake's NixOS configuration ## 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 ```bash
# 1. Generate a new SSH key with a strong passphrase # 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 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`), Then follow the instructions in [../secrets/README.md](../secrets/README.md) to rekey all my secrets
so that agenix can decrypt them automatically on the new host when I deploy my NixOS configuration. 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: After all these steps, we can finally deploy the main flake's NixOS configuration by:
@@ -270,8 +278,10 @@ cd ~/nix-config
just hypr 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 ## Change LUKS2's passphrase
+21 -12
View File
@@ -1,16 +1,20 @@
# Nix Environment Setup for Host: 12Kingdoms - Shoukei # 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://wiki.t2linux.org/distributions/nixos/installation/
> https://github.com/NixOS/nixos-hardware/tree/master/apple/t2 > 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 ## 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 ### 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 ```bash
lsblk lsblk
# show cryptsetup's compiled in defualts # show cryptsetup's compiled in defaults
cryptsetup --help cryptsetup --help
# NOTE: `cat shoukei.md | grep luks > format.sh` to generate this script # 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 cryptsetup luksDump /dev/nvme0n1p4
# open(unlock) the device with the passphrase you just set # 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 # show disk status
lsblk lsblk
@@ -86,7 +90,7 @@ Formatting the root partition:
```bash ```bash
# NOTE: `cat shoukei.md | egrep "create-btrfs" > create-btrfs.sh` to generate this script # NOTE: `cat shoukei.md | egrep "create-btrfs" > create-btrfs.sh` to generate this script
# format the root partition with btrfs and label it # 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 the root partition and create subvolumes
mount /dev/mapper/crypted-nixos /mnt # create-btrfs mount /dev/mapper/crypted-nixos /mnt # create-btrfs
btrfs subvolume create /mnt/@nix # create-btrfs btrfs subvolume create /mnt/@nix # create-btrfs
@@ -135,7 +139,7 @@ $ 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 ├─nvme0n1p1 259:2 0 600M 0 part /mnt/boot
└─nvme0n1p4 259:3 0 1.8T 0 part └─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/persistent
/mnt/snapshots /mnt/snapshots
/mnt/nix /mnt/nix
@@ -201,7 +205,7 @@ nixos-enter
mv /etc/machine-id /persistent/etc/ mv /etc/machine-id /persistent/etc/
mv /etc/ssh /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 -f /mnt/etc/nixos
rm ~/nix-config/hosts/idols_ai/hardware-configuration-new.nix rm ~/nix-config/hosts/idols_ai/hardware-configuration-new.nix
@@ -226,7 +230,8 @@ And then reboot.
## Deploying the main flake's NixOS configuration ## 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 ```bash
# 1. Generate a new SSH key with a strong passphrase # 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 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`), Then follow the instructions in [../secrets/README.md](../secrets/README.md) to rekey all my secrets
so that agenix can decrypt them automatically on the new host when I deploy my NixOS configuration. 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: 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 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)
+17 -14
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, 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. otherwise, it will be difficult to manage and maintain them.
The number of my machines has grown to more than 20, The number of my machines has grown to more than 20, and the increase in scale has shown signs of
and the increase in scale has shown signs of getting out of control of complexity, getting out of control of complexity, so it is a natural and reasonable choice to use this
so it is a natural and reasonable choice to use this fine-grained architecture to manage. fine-grained architecture to manage.
## Tests ## Tests
Testing is not necessary when your configuration is not complex, Testing is not necessary when your configuration is not complex, but with the increase in the number
but with the increase in the number and configuration of your machines, testing becomes more and more important. and configuration of your machines, testing becomes more and more important.
We have two types of tests: eval tests and nixos tests, We have two types of tests: eval tests and nixos tests, both of which can help us detect many
both of which can help us detect many obscure errors early, obscure errors early, so as to avoid testing directly in the real world, and to avoid failures in
so as to avoid testing directly in the real world, and to avoid failures in personal computers and even corporate online environments. personal computers and even corporate online environments.
Related projects & docs: Related projects & docs:
@@ -30,9 +30,9 @@ Related projects & docs:
> TODO: More Tests! > TODO: More Tests!
Eval Tests evaluate the expressions and compare the results with the expected results. Eval Tests evaluate the expressions and compare the results with the expected results. It runs fast,
It runs fast, but it doesn't build a real machine. but it doesn't build a real machine. We use eval tests to ensure that some attributes are correctly
We use eval tests to ensure that some attributes are correctly set for each NixOS host(not Darwin). set for each NixOS host(not Darwin).
How to run all the eval tests: How to run all the eval tests:
@@ -45,12 +45,15 @@ nix eval .#evalTests --show-trace --print-build-logs --verbose
> WIP: not working yet > WIP: not working yet
NixOS Tests builds and starts virtual machines using our NixOS configuration and run tests on them. 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: 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. - [ ] We need a private cache server, so that our NixOS tests do not need to build some custom
- [ ] Cannot test the whole host, because my host relies on its unique ssh host key to decrypt its agenix secrets. 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? - [ ] Maybe it's better to test every service separately, not the whole host?
How to run NixOS tests for every host: How to run NixOS tests for every host:
+1 -1
View File
@@ -104,7 +104,7 @@ in {
settings = { settings = {
typos = { typos = {
write = true; # Automatically fix typos write = true; # Automatically fix typos
ignored-words = []; configPath = "../.typos.toml";
}; };
prettier = { prettier = {
write = true; # Automatically format files write = true; # Automatically format files
+6 -4
View File
@@ -2,8 +2,10 @@
Overlays for both NixOS and Nix-Darwin. 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). 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/)
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/)
+10 -6
View File
@@ -4,18 +4,22 @@ Useful for Linux(fcitx5-rime) & macOS(squirrel).
## Linux(fcitx5-rime) ## 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 1. pay attention to the `rm -rf .local/share/fcitx5/rime/`, which may contains some auto generated
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. rime config files, which may cause flypy not the default scheme for rime
3. fcitx5-rime still cannot use on vscode & chrome now... need more time to figure out why and resolve it. 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) ## 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 ## Docs about fcitx5
- [Fcitx5 - Arch Linux Wiki](https://wiki.archlinux.org/title/Fcitx5) - [Fcitx5 - Arch Linux Wiki](https://wiki.archlinux.org/title/Fcitx5)
- [Fcitx5 - Official Wiki](https://fcitx-im.org/wiki/Fcitx_5/zh-cn) - [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) - [hyprland issue about fcitx5](https://github.com/hyprwm/Hyprland/discussions/421)
@@ -1,41 +1,38 @@
customization: customization:
distribution_code_name: Squirrel distribution_code_name: Squirrel
distribution_version: 2019-06-23 distribution_version: 2019-06-23
rime_version: 1.5.3 rime_version: 1.5.3
patch: patch:
schema_list: schema_list:
- schema: flypy # 添加小鹤音形 - schema: flypy # 添加小鹤音形
# #
# 可用的按键有 Caps_Lock, Shift_L, Shift_R, Control_L, control_R # 可用的按键有 Caps_Lock, Shift_L, Shift_R, Control_L, control_R
# Mac 系统上的鼠须管不能区分左、右,因此只有对 Shift_L, Control_L 的设定起作用 # Mac 系统上的鼠须管不能区分左、右,因此只有对 Shift_L, Control_L 的设定起作用
# #
# 已输入编码时按切换键,可以进一步设定输入法中西文切换的形式 # 已输入编码时按切换键,可以进一步设定输入法中西文切换的形式
# 可选的临时切换策略有三: # 可选的临时切换策略有三:
# inline_ascii 在输入法的临时西文编辑区内输入字母、数字、符号、空格等,回车上屏后自动复位到中文 # inline_ascii 在输入法的临时西文编辑区内输入字母、数字、符号、空格等,回车上屏后自动复位到中文
# commit_text 已输入的候选文字上屏并切换至西文输入模式 # commit_text 已输入的候选文字上屏并切换至西文输入模式
# commit_code 已输入的编码字符上屏并切换至西文输入模式 # commit_code 已输入的编码字符上屏并切换至西文输入模式
# 设为 noop, 屏蔽该切换键 # 设为 noop, 屏蔽该切换键
# #
# 如果要把Caps Lock 设为只改变字母的大小写而不做中西文切换,可将 Caps_Lock 对应的切换方式设为 noop # 如果要把Caps Lock 设为只改变字母的大小写而不做中西文切换,可将 Caps_Lock 对应的切换方式设为 noop
# 如果要以Caps Lock 切换到西文模式,默认输出小写字母,请置 ascii_composer/good_old_caps_lock: false # 如果要以Caps Lock 切换到西文模式,默认输出小写字母,请置 ascii_composer/good_old_caps_lock: false
# 如果要以Caps Lock 切换到西文模式,默认输出大写字母,请置 ascii_composer/good_old_caps_lock: true # 如果要以Caps Lock 切换到西文模式,默认输出大写字母,请置 ascii_composer/good_old_caps_lock: true
ascii_composer/good_old_caps_lock: true ascii_composer/good_old_caps_lock: true
ascii_composer/switch_key: ascii_composer/switch_key:
Caps_Lock: noop Caps_Lock: noop
Shift_L: commit_code Shift_L: commit_code
Shift_R: noop Shift_R: noop
Control_L: noop Control_L: noop
Control_R: noop Control_R: noop
key_binder/bindings: key_binder/bindings:
- when: paging - when: paging
accept: bracketleft accept: bracketleft
send: Page_Up send: Page_Up
- when: has_menu - when: has_menu
accept: bracketright accept: bracketright
send: Page_Down send: Page_Down
@@ -24,74 +24,73 @@ menu:
page_size: 5 page_size: 5
punctuator: punctuator:
full_shape: # replace full_shape with half_shape full_shape: # replace full_shape with half_shape
',' : { commit: } ",": { commit: }
'.' : { commit: 。 } ".": { commit: 。 }
'<' : [ 《, 〈, «, ] "<": [《, 〈, «, ]
'>' : [ 》, 〉, », ] ">": [》, 〉, », ]
'/' : { commit: 、 } "/": { commit: 、 }
'?' : { commit: } "?": { commit: }
';' : { commit: } ";": { commit: }
':' : { commit: } ":": { commit: }
'''' : { pair: [ '', '' ] } "'": { pair: ["", ""] }
'"' : { pair: [ '“', '”' ] } '"': { pair: ["“", "”"] }
'\' : { commit: 、 } '\': { commit: 、 }
'|' : '|' "|": "|"
'`' : '`' "`": "`"
'~' : { commit: } "~": { commit: }
'!' : { commit: } "!": { commit: }
'@' : '@' "@": "@"
'#' : '#' "#": "#"
'%' : { commit: '%' } "%": { commit: "%" }
'$' : { commit: "$" } "$": { commit: "$" }
'^' : { commit: …… } "^": { commit: …… }
'&' : '&' "&": "&"
'*' : { commit: '*' } "*": { commit: "*" }
'(' : "(":
')' : ")":
'-' : '-' "-": "-"
'_' : —— "_": ——
'+' : '+' "+": "+"
'=' : '=' "=": "="
'[' : [ 「, 【, , ] "[": [「, 【, , ]
']' : [ 」, 】, , ] "]": [」, 】, , ]
'{' : [ 『, 〖, ] "{": [『, 〖, ]
'}' : [ 』, 〗, ] "}": [』, 〗, ]
half_shape: half_shape:
',' : { commit: } ",": { commit: }
'.' : { commit: 。 } ".": { commit: 。 }
'<' : [ 《, 〈, «, ] "<": [《, 〈, «, ]
'>' : [ 》, 〉, », ] ">": [》, 〉, », ]
'/' : { commit: 、 } "/": { commit: 、 }
'?' : { commit: } "?": { commit: }
';' : { commit: } ";": { commit: }
':' : { commit: } ":": { commit: }
'''' : { pair: [ '', '' ] } "'": { pair: ["", ""] }
'"' : { pair: [ '“', '”' ] } '"': { pair: ["“", "”"] }
'\' : { commit: 、 } '\': { commit: 、 }
'|' : '|' "|": "|"
'`' : '`' "`": "`"
'~' : { commit: } "~": { commit: }
'!' : { commit: } "!": { commit: }
'@' : '@' "@": "@"
'#' : '#' "#": "#"
'%' : { commit: '%' } "%": { commit: "%" }
'$' : { commit: "$" } "$": { commit: "$" }
'^' : { commit: …… } "^": { commit: …… }
'&' : '&' "&": "&"
'*' : { commit: '*' } "*": { commit: "*" }
'(' : "(":
')' : ")":
'-' : '-' "-": "-"
'_' : —— "_": ——
'+' : '+' "+": "+"
'=' : '=' "=": "="
'[' : [ 「, 【, , ] "[": [「, 【, , ]
']' : [ 」, 】, , ] "]": [」, 】, , ]
'{' : [ 『, 〖, ] "{": [『, 〖, ]
'}' : [ 』, 〗, ] "}": [』, 〗, ]
key_binder: key_binder:
bindings: bindings:
@@ -16,14 +16,14 @@ punctuator:
switches: switches:
- name: ascii_mode - name: ascii_mode
reset: 0 reset: 0
# states: [ 中文, 英文 ] # states: [ 中文, 英文 ]
- name: full_shape - name: full_shape
# states: [ 半角, 全角 ] # states: [ 半角, 全角 ]
- name: simplification - name: simplification
# states: [ 简, 繁 ] # states: [ 简, 繁 ]
reset: 0 reset: 0
- name: ascii_punct - name: ascii_punct
# states: [ 。,, ., ] # states: [ 。,, ., ]
reset: 0 reset: 0
engine: engine:
@@ -61,11 +61,11 @@ engine:
speller: speller:
alphabet: "abcdefghijklmnopqrstuvwxyz;'" alphabet: "abcdefghijklmnopqrstuvwxyz;'"
initials: ';abcdefghijklmnopqrstuvwxyz' initials: ";abcdefghijklmnopqrstuvwxyz"
finals: "'" finals: "'"
#delimiter: " '" #delimiter: " '"
max_code_length: 4 max_code_length: 4
auto_select: true #顶字上屏 auto_select: true #顶字上屏
auto_select_pattern: ^;.$|^\w{4}$ auto_select_pattern: ^;.$|^\w{4}$
auto_clear: max_length #manual|auto|max_length 空码按下一键确认清屏|空码自动清|达到最长码时后码顶上清屏 auto_clear: max_length #manual|auto|max_length 空码按下一键确认清屏|空码自动清|达到最长码时后码顶上清屏
@@ -77,13 +77,12 @@ translator:
enable_user_dict: false enable_user_dict: false
disable_user_dict_for_patterns: disable_user_dict_for_patterns:
- "^z.*$" - "^z.*$"
history: history:
input: ;f input: ;f
size: 1 #重复前几次上屏 size: 1 #重复前几次上屏
initial_quality: 1 #首选 initial_quality: 1 #首选
simplification: simplification:
opencc_config: s2tw.json opencc_config: s2tw.json
option_name: simplification option_name: simplification
@@ -96,7 +95,7 @@ custom_phraseVD:
enable_sentence: false enable_sentence: false
enable_completion: false enable_completion: false
initial_quality: 0 #用户词和系统词重码 置顶 initial_quality: 0 #用户词和系统词重码 置顶
custom_phraseXT: custom_phraseXT:
dictionary: "" dictionary: ""
user_dict: flypy_sys user_dict: flypy_sys
@@ -112,7 +111,7 @@ custom_phraseYH:
enable_sentence: false enable_sentence: false
enable_completion: false enable_completion: false
initial_quality: -1 #用户词和系统词重码居后 initial_quality: -1 #用户词和系统词重码居后
custom_phraseQMZ: custom_phraseQMZ:
dictionary: "" dictionary: ""
user_dict: flypy_full user_dict: flypy_full
@@ -124,27 +123,26 @@ custom_phraseQMZ:
reverse_lookup: reverse_lookup:
dictionary: flypydz dictionary: flypydz
comment_format: comment_format:
# - xform/^// # - xform/^//
# - xform/$// # - xform/$//
- xform/ / / - xform/ / /
key_binder: key_binder:
import_preset: default #方案切换相关 import_preset: default #方案切换相关
bindings: bindings:
- {accept: bracketleft, send: Page_Up, when: paging} # [上翻页 - { accept: bracketleft, send: Page_Up, when: paging } # [上翻页
- {accept: bracketright, send: Page_Down, when: has_menu} # ]下翻页 - { accept: bracketright, send: Page_Down, when: has_menu } # ]下翻页
- {accept: comma, send: comma, when: paging} #注销逗号翻页 - { accept: comma, send: comma, when: paging } #注销逗号翻页
- {accept: period, send: period, when: has_menu} #注销句号翻页 - { accept: period, send: period, when: has_menu } #注销句号翻页
- {accept: semicolon, send: 2, when: has_menu} #分号次选 - { accept: semicolon, send: 2, when: has_menu } #分号次选
# - {accept: Release+semicolon, send: semicolon, when: has_menu} #如启用此行,则分号引导符号功能无效 # - {accept: Release+semicolon, send: semicolon, when: has_menu} #如启用此行,则分号引导符号功能无效
- {accept: Release+period, send: period, when: composing} #句号顶屏 - { accept: Release+period, send: period, when: composing } #句号顶屏
- {accept: Release+comma, send: comma, when: composing} #逗号顶屏 - { accept: Release+comma, send: comma, when: composing } #逗号顶屏
- {accept: "Tab", send: Escape, when: composing} - { accept: "Tab", send: Escape, when: composing }
- {accept: "Shift_R", send: Escape, when: composing} - { accept: "Shift_R", send: Escape, when: composing }
- {accept: "Shift+space", toggle: full_shape, when: always} #切换全半角 - { accept: "Shift+space", toggle: full_shape, when: always } #切换全半角
- {accept: "Control+period", toggle: ascii_punct, when: always} #切换中英标点 - { accept: "Control+period", toggle: ascii_punct, when: always } #切换中英标点
- {accept: "Control+j", toggle: simplification, when: always} #切换简繁 - { accept: "Control+j", toggle: simplification, when: always } #切换简繁
recognizer: recognizer:
import_preset: default import_preset: default
@@ -157,7 +155,6 @@ recognizer:
menu: menu:
page_size: 5 #候选项数 page_size: 5 #候选项数
style: style:
horizontal: true #竖排为false horizontal: true #竖排为false
@@ -1,39 +1,38 @@
customization: customization:
distribution_code_name: squirrel distribution_code_name: squirrel
distribution_version: 0.14.0 distribution_version: 0.14.0
generator: "squirrel::UIStyleSettings" generator: "squirrel::UIStyleSettings"
modified_time: "2019-06-23" modified_time: "2019-06-23"
rime_version: 1.5.3 rime_version: 1.5.3
patch: patch:
"preset_color_schemes/metro": "preset_color_schemes/metro":
author: "flypy.com" author: "flypy.com"
back_color: 0xffffff # 候选条背景色 back_color: 0xffffff # 候选条背景色
border_color_width: 1 border_color_width: 1
#border_color: 0xe89f00 # 边框色 #border_color: 0xe89f00 # 边框色
#preedit_back_color: 0xf0403516 #新增,未知其意 #preedit_back_color: 0xf0403516 #新增,未知其意
border_height: 8 # 窗口边界高度,大于圆角半径才生效 border_height: 8 # 窗口边界高度,大于圆角半径才生效
border_width: 8 # 窗口边界宽度,大于圆角半径才生效 border_width: 8 # 窗口边界宽度,大于圆角半径才生效
candidate_format: "%c\u2005%@\u2005" # 用 1/6 em 空格 U+2005 来控制编号 %c 和候选词 %@ 前后的空间。 candidate_format: "%c\u2005%@\u2005" # 用 1/6 em 空格 U+2005 来控制编号 %c 和候选词 %@ 前后的空间。
corner_radius: 6 # 窗口圆角半径 corner_radius: 6 # 窗口圆角半径
#hilited_corner_radius: 6 # 高亮圆角 #hilited_corner_radius: 6 # 高亮圆角
hilited_text_color: 0x000000 # 编码高亮 hilited_text_color: 0x000000 # 编码高亮
hilited_back_color: 0xffffff # 编码背景高亮 hilited_back_color: 0xffffff # 编码背景高亮
hilited_candidate_label_color: 0xeeeeee # 首选编号色 hilited_candidate_label_color: 0xeeeeee # 首选编号色
hilited_candidate_text_color: 0xffffff # 首选文字色 hilited_candidate_text_color: 0xffffff # 首选文字色
hilited_candidate_back_color: 0xe89f00 # 首选背景色 hilited_candidate_back_color: 0xe89f00 # 首选背景色
hilited_comment_text_color: 0xcccccc # 首选提示字母色 hilited_comment_text_color: 0xcccccc # 首选提示字母色
label_color: 0x555555 # 次选编号色 label_color: 0x555555 # 次选编号色
candidate_text_color: 0x000000 # 次选文字色 candidate_text_color: 0x000000 # 次选文字色
candidate_back_color: 0xffffff # 次选背景色 candidate_back_color: 0xffffff # 次选背景色
comment_text_color: 0x555555 # 次选提示字母色 comment_text_color: 0x555555 # 次选提示字母色
horizontal: true # 候选窗横向显示 horizontal: true # 候选窗横向显示
font_point: 18 # 候选窗文字字号 font_point: 18 # 候选窗文字字号
label_font_point: 14 # 候选窗编号字号 label_font_point: 14 # 候选窗编号字号
inline_preedit: true # 开启嵌入编码 inline_preedit: true # 开启嵌入编码
name: "metro" name: "metro"
text_color: 0x333333 # 编码行文字颜色,24位色值,16进制,BGR顺序 text_color: 0x333333 # 编码行文字颜色,24位色值,16进制,BGR顺序
"style/line_spacing": 12 # 候选词的行间距 "style/line_spacing": 12 # 候选词的行间距
"style/color_scheme": metro "style/color_scheme": metro
"style/display_tray_icon": false "style/display_tray_icon": false
"style/text_orientation": horizontal # horizontal | vertical "style/text_orientation": horizontal # horizontal | vertical
@@ -1,12 +1,12 @@
# Squirrel settings # Squirrel settings
# encoding: utf-8 # encoding: utf-8
config_version: '0.37' config_version: "0.37"
us_keyboard_layout: true us_keyboard_layout: true
# for veteran chord-typist # for veteran chord-typist
chord_duration: 0.1 # seconds chord_duration: 0.1 # seconds
# options: always | never | appropriate # options: always | never | appropriate
show_notifications_when: appropriate show_notifications_when: appropriate
@@ -22,7 +22,7 @@ style:
# NOTE: do not set a default value for `candidate_list_layout`, in order to # NOTE: do not set a default value for `candidate_list_layout`, in order to
# keep the deprecated `horizontal` option working for existing users. # keep the deprecated `horizontal` option working for existing users.
#candidate_list_layout: stacked # stacked | linear #candidate_list_layout: stacked # stacked | linear
text_orientation: horizontal # horizontal | vertical text_orientation: horizontal # horizontal | vertical
inline_preedit: true inline_preedit: true
corner_radius: 10 corner_radius: 10
@@ -38,7 +38,7 @@ style:
# adjust the base line of vertical text # adjust the base line of vertical text
#base_offset: 6 #base_offset: 6
font_face: 'Lucida Grande' font_face: "Lucida Grande"
font_point: 21 font_point: 21
#label_font_face: 'Lucida Grande' #label_font_face: 'Lucida Grande'
label_font_point: 18 label_font_point: 18
@@ -117,7 +117,7 @@ preset_color_schemes:
hilited_text_color: 0xffcf9a hilited_text_color: 0xffcf9a
hilited_back_color: 0x222222 hilited_back_color: 0x222222
hilited_candidate_text_color: 0x92f6da hilited_candidate_text_color: 0x92f6da
hilited_candidate_back_color: 0x10000000 # 0x333333 hilited_candidate_back_color: 0x10000000 # 0x333333
comment_text_color: 0x606cff comment_text_color: 0x606cff
psionics: psionics:
@@ -203,7 +203,7 @@ preset_color_schemes:
name: 简约白/Clean White name: 简约白/Clean White
author: Chongyu Zhu <lembacon@gmail.com>, based on 搜狗「简约白」 author: Chongyu Zhu <lembacon@gmail.com>, based on 搜狗「简约白」
horizontal: true horizontal: true
candidate_format: '%c %@' candidate_format: "%c %@"
corner_radius: 6 corner_radius: 6
border_height: 6 border_height: 6
border_width: 6 border_width: 6
@@ -222,72 +222,72 @@ preset_color_schemes:
apathy: apathy:
name: 冷漠/Apathy name: 冷漠/Apathy
author: LIANG Hai author: LIANG Hai
horizontal: true # 水平排列 horizontal: true # 水平排列
inline_preedit: true #单行显示,false双行显示 inline_preedit: true #单行显示,false双行显示
candidate_format: "%c\u2005%@\u2005" # 编号 %c 和候选词 %@ 前后的空间 candidate_format: "%c\u2005%@\u2005" # 编号 %c 和候选词 %@ 前后的空间
corner_radius: 5 #候选条圆角 corner_radius: 5 #候选条圆角
border_height: 0 border_height: 0
border_width: 0 border_width: 0
back_color: 0xFFFFFF #候选条背景色 back_color: 0xFFFFFF #候选条背景色
font_face: "PingFangSC-Regular,HanaMinB" #候选词字体 font_face: "PingFangSC-Regular,HanaMinB" #候选词字体
font_point: 16 #候选字词大小 font_point: 16 #候选字词大小
text_color: 0x424242 #高亮选中词颜色 text_color: 0x424242 #高亮选中词颜色
label_font_face: "STHeitiSC-Light" #候选词编号字体 label_font_face: "STHeitiSC-Light" #候选词编号字体
label_font_point: 12 #候选编号大小 label_font_point: 12 #候选编号大小
hilited_candidate_text_color: 0xEE6E00 #候选文字颜色 hilited_candidate_text_color: 0xEE6E00 #候选文字颜色
hilited_candidate_back_color: 0xFFF0E4 #候选文字背景色 hilited_candidate_back_color: 0xFFF0E4 #候选文字背景色
comment_text_color: 0x999999 #拼音等提示文字颜色 comment_text_color: 0x999999 #拼音等提示文字颜色
dust: dust:
name: 浮尘/Dust name: 浮尘/Dust
author: Superoutman <asticosmo@gmail.com> author: Superoutman <asticosmo@gmail.com>
horizontal: true # 水平排列 horizontal: true # 水平排列
inline_preedit: true #单行显示,false双行显示 inline_preedit: true #单行显示,false双行显示
candidate_format: "%c\u2005%@\u2005" # 用 1/6 em 空格 U+2005 来控制编号 %c 和候选词 %@ 前后的空间。 candidate_format: "%c\u2005%@\u2005" # 用 1/6 em 空格 U+2005 来控制编号 %c 和候选词 %@ 前后的空间。
corner_radius: 2 #候选条圆角 corner_radius: 2 #候选条圆角
border_height: 3 # 窗口边界高度,大于圆角半径才生效 border_height: 3 # 窗口边界高度,大于圆角半径才生效
border_width: 8 # 窗口边界宽度,大于圆角半径才生效 border_width: 8 # 窗口边界宽度,大于圆角半径才生效
back_color: 0xeeffffff #候选条背景色 back_color: 0xeeffffff #候选条背景色
border_color: 0xE0B693 # 边框色 border_color: 0xE0B693 # 边框色
font_face: "HYQiHei-55S Book,HanaMinA Regular" #候选词字体 font_face: "HYQiHei-55S Book,HanaMinA Regular" #候选词字体
font_point: 14 #候选字词大小 font_point: 14 #候选字词大小
label_font_face: "SimHei" #候选词编号字体 label_font_face: "SimHei" #候选词编号字体
label_font_point: 10 #候选编号大小 label_font_point: 10 #候选编号大小
label_color: 0xcbcbcb # 预选栏编号颜色 label_color: 0xcbcbcb # 预选栏编号颜色
candidate_text_color: 0x555555 # 预选项文字颜色 candidate_text_color: 0x555555 # 预选项文字颜色
text_color: 0x424242 # 拼音行文字颜色,24位色值,16进制,BGR顺序 text_color: 0x424242 # 拼音行文字颜色,24位色值,16进制,BGR顺序
comment_text_color: 0x999999 # 拼音等提示文字颜色 comment_text_color: 0x999999 # 拼音等提示文字颜色
hilited_text_color: 0x9e9e9e # 高亮拼音 (需要开启内嵌编码) hilited_text_color: 0x9e9e9e # 高亮拼音 (需要开启内嵌编码)
hilited_candidate_text_color: 0x000000 # 第一候选项文字颜色 hilited_candidate_text_color: 0x000000 # 第一候选项文字颜色
hilited_candidate_back_color: 0xfff0e4 # 第一候选项背景背景色 hilited_candidate_back_color: 0xfff0e4 # 第一候选项背景背景色
hilited_candidate_label_color: 0x555555 # 第一候选项编号颜色 hilited_candidate_label_color: 0x555555 # 第一候选项编号颜色
hilited_comment_text_color: 0x9e9e9e # 注解文字高亮 hilited_comment_text_color: 0x9e9e9e # 注解文字高亮
mojave_dark: mojave_dark:
name: 沙漠夜/Mojave Dark name: 沙漠夜/Mojave Dark
author: xiehuc <xiehuc@gmail.com> author: xiehuc <xiehuc@gmail.com>
horizontal: true # 水平排列 horizontal: true # 水平排列
inline_preedit: true # 单行显示,false双行显示 inline_preedit: true # 单行显示,false双行显示
candidate_format: "%c\u2005%@" # 用 1/6 em 空格 U+2005 来控制编号 %c 和候选词 %@ 前后的空间。 candidate_format: "%c\u2005%@" # 用 1/6 em 空格 U+2005 来控制编号 %c 和候选词 %@ 前后的空间。
corner_radius: 5 # 候选条圆角 corner_radius: 5 # 候选条圆角
hilited_corner_radius: 3 # 高亮圆角 hilited_corner_radius: 3 # 高亮圆角
border_height: 6 # 窗口边界高度,大于圆角半径才生效 border_height: 6 # 窗口边界高度,大于圆角半径才生效
border_width: 6 # 窗口边界宽度,大于圆角半径才生效 border_width: 6 # 窗口边界宽度,大于圆角半径才生效
font_face: "PingFangSC" # 候选词字体 font_face: "PingFangSC" # 候选词字体
font_point: 16 # 候选字词大小 font_point: 16 # 候选字词大小
label_font_point: 14 # 候选编号大小 label_font_point: 14 # 候选编号大小
text_color: 0xdedddd # 拼音行文字颜色,24位色值,16进制,BGR顺序 text_color: 0xdedddd # 拼音行文字颜色,24位色值,16进制,BGR顺序
back_color: 0x252320 # 候选条背景色 back_color: 0x252320 # 候选条背景色
label_color: 0x888785 # 预选栏编号颜色 label_color: 0x888785 # 预选栏编号颜色
border_color: 0x020202 # 边框色 border_color: 0x020202 # 边框色
candidate_text_color: 0xdedddd # 预选项文字颜色 candidate_text_color: 0xdedddd # 预选项文字颜色
hilited_text_color: 0xdedddd # 高亮拼音 (需要开启内嵌编码) hilited_text_color: 0xdedddd # 高亮拼音 (需要开启内嵌编码)
hilited_back_color: 0x252320 # 高亮拼音 (需要开启内嵌编码) hilited_back_color: 0x252320 # 高亮拼音 (需要开启内嵌编码)
hilited_candidate_text_color: 0xffffff # 第一候选项文字颜色 hilited_candidate_text_color: 0xffffff # 第一候选项文字颜色
hilited_candidate_back_color: 0xcb5d00 # 第一候选项背景背景色 hilited_candidate_back_color: 0xcb5d00 # 第一候选项背景背景色
hilited_candidate_label_color: 0xffffff # 第一候选项编号颜色 hilited_candidate_label_color: 0xffffff # 第一候选项编号颜色
comment_text_color: 0xdedddd # 拼音等提示文字颜色 comment_text_color: 0xdedddd # 拼音等提示文字颜色
#hilited_comment_text_color: 0xdedddd # 注解文字高亮 #hilited_comment_text_color: 0xdedddd # 注解文字高亮
solarized_light: solarized_light:
@@ -342,9 +342,9 @@ app_options:
ascii_mode: true ascii_mode: true
no_inline: true no_inline: true
org.vim.MacVim: org.vim.MacVim:
ascii_mode: true # 初始爲西文模式 ascii_mode: true # 初始爲西文模式
no_inline: true # 不使用行內編輯 no_inline: true # 不使用行內編輯
vim_mode: true # 退出VIM插入模式自動切換輸入法狀態 vim_mode: true # 退出VIM插入模式自動切換輸入法狀態
com.apple.dt.Xcode: com.apple.dt.Xcode:
ascii_mode: true ascii_mode: true
com.barebones.textwrangler: com.barebones.textwrangler:
@@ -369,4 +369,4 @@ app_options:
inline: true inline: true
ru.keepcoder.Telegram: ru.keepcoder.Telegram:
# 規避 https://github.com/rime/squirrel/issues/475 # 規避 https://github.com/rime/squirrel/issues/475
inline: true inline: true
+33 -21
View File
@@ -1,24 +1,31 @@
# Secrets Management # 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 encryption is done by using all my host's public keys(`/etc/ssh/ssh_host_ed25519_key`), so that
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. 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`, In this way, all secrets is still encrypted when transmitted over the network and written to
they are decrypted only when they are finally used. `/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 ## Adding or Updating Secrets
> All the operations in this section should be performed in my private repository: `nix-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: 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: Suppose you want to add a new secret file `xxx.age`. Follow these steps:
1. Navigate to your private `nix-secrets` repository. 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 ```nix
# This file is not imported into your NixOS configuration. It is only used for the agenix CLI. # 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 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`, `agenix` will encrypt the file with all the public keys we defined in `secrets.nix`, so all the
so all the users and systems defined in `secrets.nix` can decrypt it with their private keys. users and systems defined in `secrets.nix` can decrypt it with their private keys.
## Deploying Secrets ## Deploying Secrets
> All the operations in this section should be performed in this repository. > 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 ```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`. From now on, every time you run `nixos-rebuild switch`, it will decrypt the secrets using the
It will then symlink the secrets to the path defined by the `age.secrets.<name>.path` argument, which defaults to `/etc/secrets`. 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 ## 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: 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`. 2. Commit and push the changes to `nix-secrets`.
3. On the new host: 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 ## Other Replacements
- [ragenix](https://github.com/yaxitech/ragenix): A Rust reimplementation of agenix. - [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. - with a type-safe language like Rust, we can get a better error message and less bugs.
+1 -1
View File
@@ -35,7 +35,7 @@ in {
server.operation.enable = mkEnableOption "NixOS Secrets for Operation Servers(Backup, Monitoring, etc)"; server.operation.enable = mkEnableOption "NixOS Secrets for Operation Servers(Backup, Monitoring, etc)";
server.kubernetes.enable = mkEnableOption "NixOS Secrets for Kubernetes"; 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 = config =
-2
View File
@@ -1,5 +1,3 @@
# Variables # Variables
Some common variables that I use in my NixOS configuration. Some common variables that I use in my NixOS configuration.