Initial commit
This commit is contained in:
commit
a4db9c8516
36 changed files with 15659 additions and 0 deletions
79
literal/virtualization/nebula-sync.org
Normal file
79
literal/virtualization/nebula-sync.org
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
#+title: Nebula Sync
|
||||
|
||||
* Nebula Sync Configuration
|
||||
#+begin_src nix :noweb yes :tangle ~/Development/falcon_nest/virtualization/nebula-sync-oci.nix
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
{
|
||||
|
||||
<<nebula-user>>
|
||||
|
||||
<<sops>>
|
||||
|
||||
<<oci-container>>
|
||||
|
||||
}
|
||||
#+end_src
|
||||
** Version number
|
||||
I'm putting the version number at the start of this file just below the configuration file skeleton. The goal is to receive an update that a new version is ready, then update this version number to the new version and tangle the code block. Then, commit both this Org file and the generated file to Git for the pipeline to run.
|
||||
|
||||
You may ask, why not just use the "latest" tag? It makes sense. If I'm updating the container image manually, I wouldn't need to change anything, just run `nixos-rebuild-switch` when I get word of a new release. The virtue of Nix and NixOS, however, is that I can make my setup reproducible with respects to not only the NixOS version, but the Docker image version. Plus, it provides a historical record of the container on Crow's Nest and Git, not to mention, if I shut down and wipe clean the container, then decide I need it again, I can go right back to the last known working version.
|
||||
#+NAME: version-number
|
||||
#+begin_src nix :noweb-ref version-number
|
||||
0.11.2
|
||||
#+end_src
|
||||
** Set up the nebula user
|
||||
Each container on this system gets its own user.
|
||||
#+NAME: nebula-user
|
||||
#+begin_src nix :noweb-ref nebula-user
|
||||
users.users.nebula = {
|
||||
isSystemUser = true;
|
||||
group = "podman";
|
||||
home = "/var/lib/nebula";
|
||||
linger = false;
|
||||
createHome = true;
|
||||
autoSubUidGidRange = true;
|
||||
};
|
||||
#+end_src
|
||||
** Set up secrets
|
||||
The setup for nebula-sync requires the user to put in two environment variables,
|
||||
one for the primary Pi-Hole instance and one for what it calls replicas or the
|
||||
secondary instances. Each of these variables is a string consisting of the IP
|
||||
address followed by a pipe symbol then the admin or app password for
|
||||
the instance.
|
||||
|
||||
Obviously, having passwords in the configuration file wouldn't do so I decided to use sops-nix to manage secrets. After a bit of finessing, it works well, you just have to use environmentFiles for any oci-containers since the end result of the secrets management is a single file with the necessary information inside and you'll need to reference that file.
|
||||
#+NAME: sops
|
||||
#+begin_src nix :noweb-ref sops
|
||||
sops = {
|
||||
secrets = {
|
||||
nebula-sync-env = {
|
||||
sopsFile = ../secrets/nebula-sync.env;
|
||||
format = "dotenv";
|
||||
owner = config.users.users.nebula.name;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
#+end_src
|
||||
** Configure the container
|
||||
Then we bring it all together. I'm skipping TLS verification for now, though I plan on going back and setting up the Pi-Holes with a proper domain name and SSL certificate. Plan on being the keyphrase here.
|
||||
|
||||
Cron is set to run at 23 minutes past the hour. We won't do a full sync, but we'll ensure gravity is updated after each run.
|
||||
#+NAME: oci-container
|
||||
#+begin_src nix :noweb yes :noweb-ref oci-container
|
||||
virtualisation.oci-containers.containers.nebula-sync = {
|
||||
autoRemoveOnStop = false;
|
||||
autoStart = false;
|
||||
image = "ghcr.io/lovelaze/nebula-sync:<<version-number>>";
|
||||
environment = {
|
||||
FULL_SYNC = "false";
|
||||
RUN_GRAVITY = "true";
|
||||
CRON = "23 * * * *";
|
||||
CLIENT_SKIP_TLS_VERIFICATION = "true";
|
||||
};
|
||||
environmentFiles = [ config.sops.secrets.nebula-sync-env.path ];
|
||||
podman = { user = "nebula"; };
|
||||
log-driver = "journald";
|
||||
};
|
||||
#+end_src
|
||||
156
literal/virtualization/setting-up-podman-and-portainer.org
Normal file
156
literal/virtualization/setting-up-podman-and-portainer.org
Normal file
|
|
@ -0,0 +1,156 @@
|
|||
* Setting up Podman and Portainer
|
||||
** Set up Podman :factcheck:
|
||||
#+begin_src nix :noweb yes :tangle ~/Development/falcon_nest/virtualization/podman-utils.nix
|
||||
{ pkgs, lib, config, ... }: {
|
||||
<<podman-utils>>
|
||||
}
|
||||
#+end_src
|
||||
NixOS seems to jive better with Podman, probably due to its ability to run without a daemon, which usually needs root access.
|
||||
|
||||
I'll be looking to run several containers the NixOS way. What does that mean? Well, no yaml, just Nix. Nix to declare the containers and Nix to declare the systemd scripts that help launch and scrap containers. However, there are some configuration options that we need to set for the VM that will host them.
|
||||
|
||||
First, I'll enable podman and specify it as the backend...:
|
||||
|
||||
#+begin_src nix
|
||||
virtualisation.podman.enable = true;
|
||||
virtualisation.oci-containers.backend = "podman";
|
||||
#+end_src
|
||||
|
||||
...and enable some sane defaults, like ensuring compatibility with Docker (so 3rd-party images play nice) and enabling automatic pruning of old images:
|
||||
|
||||
#+begin_src nix
|
||||
virtualisation.podman.autoPrune.enable = true;
|
||||
virtualisation.podman.dockerCompat = true;
|
||||
#+end_src
|
||||
|
||||
Then I'll set up DNS for all Podman networks:
|
||||
|
||||
#+begin_src nix
|
||||
networking.firewall.interfaces = let
|
||||
matchAll =
|
||||
if !config.networking.nftables.enable then "podman+" else "podman*";
|
||||
in { "${matchAll}".allowedUDPPorts = [ 53 ]; };
|
||||
#+end_src
|
||||
|
||||
Here's the completed code:
|
||||
|
||||
#+begin_src nix :noweb-ref podman-utils
|
||||
virtualisation = {
|
||||
oci-containers.backend = "podman";
|
||||
podman = {
|
||||
enable = true;
|
||||
autoPrune = {
|
||||
enable = true;
|
||||
flags = [ "--all" "--filter 'until=24h'" "--force" ];
|
||||
};
|
||||
dockerCompat = true;
|
||||
};
|
||||
};
|
||||
|
||||
networking.firewall.interfaces = let
|
||||
matchAll =
|
||||
if !config.networking.nftables.enable then "podman+" else "podman*";
|
||||
in { "${matchAll}".allowedUDPPorts = [ 53 ]; };
|
||||
|
||||
# If you want to trigger this service manually, run sudo systemctl restart update-containers.service.
|
||||
systemd.services.update-containers = {
|
||||
serviceConfig = {
|
||||
Type = "oneshot";
|
||||
ExecStart = lib.getExe (pkgs.writeShellScriptBin "update-containers" ''
|
||||
images=$(${pkgs.podman}/bin/podman ps -a --format="{{.Image}}" | sort -u)
|
||||
|
||||
for image in $images; do
|
||||
${pkgs.podman}/bin/podman pull "$image"
|
||||
done
|
||||
'');
|
||||
};
|
||||
};
|
||||
#+end_src
|
||||
** Set up Portainer
|
||||
#+begin_src nix :noweb yes :tangle ~/Development/falcon_nest/virtualization/portainer.nix
|
||||
{ pkgs, lib, config, ... }: {
|
||||
<<portainer-config>>
|
||||
}
|
||||
#+end_src
|
||||
|
||||
This virtual machine will feature a single Portainer instance to act as "mission control" for my Debian-based fileserver and a Raspberry Pi running some public-facing utilities that run a variety of Docker containers.
|
||||
|
||||
I want to be careful to run this instance properly and securely. I'll need to create a user for the Portainer container.
|
||||
|
||||
#+begin_src nix :noweb-ref portainer-config
|
||||
users.users.portainer = {
|
||||
isSystemUser = true;
|
||||
group = "podman";
|
||||
home = "/var/lib/portainer";
|
||||
createHome = true;
|
||||
};
|
||||
|
||||
#+end_src
|
||||
|
||||
Now for the actual container configuration, and this is courtesy of a great tool called [[https://github.com/aksiksi/compose2nix][compose2nix]]. compose2nix takes your standard Docker Compose YAML file and generates a configuration for the container.
|
||||
|
||||
#+begin_src nix :noweb-ref portainer-config
|
||||
virtualisation.oci-containers.containers."portainer" = {
|
||||
podman.user = "portainer";
|
||||
image = "portainer/portainer-ce:lts";
|
||||
volumes = [
|
||||
"/var/run/docker.sock:/var/run/docker.sock:rw"
|
||||
"portainer_portainer_data:/data:rw"
|
||||
];
|
||||
ports = [ "8000:8000/tcp" "9443:9443/tcp" "9000:9000/tcp" ];
|
||||
log-driver = "journald";
|
||||
extraOptions =
|
||||
[ "--network-alias=portainer" "--network=portainer_default" ];
|
||||
};
|
||||
|
||||
#+end_src
|
||||
|
||||
compose2nix also takes care of setting up the systemd service that's responsible for restarting the container when necessary, as well as setting up the volumes and networks the container will use.
|
||||
|
||||
#+begin_src nix :noweb-ref portainer-config
|
||||
# Networks
|
||||
systemd.services."podman-network-portainer_default" = {
|
||||
path = [ pkgs.podman ];
|
||||
serviceConfig = {
|
||||
Type = "oneshot";
|
||||
RemainAfterExit = true;
|
||||
ExecStop = "podman network rm -f portainer_default";
|
||||
};
|
||||
script = ''
|
||||
podman network inspect portainer_default || podman network create portainer_default
|
||||
'';
|
||||
partOf = [ "podman-compose-portainer-root.target" ];
|
||||
wantedBy = [ "podman-compose-portainer-root.target" ];
|
||||
};
|
||||
|
||||
# Volumes
|
||||
systemd.services."podman-volume-portainer_portainer_data" = {
|
||||
path = [ pkgs.podman ];
|
||||
serviceConfig = {
|
||||
Type = "oneshot";
|
||||
RemainAfterExit = true;
|
||||
};
|
||||
script = ''
|
||||
podman volume inspect portainer_portainer_data || podman volume create portainer_portainer_data
|
||||
'';
|
||||
partOf = [ "podman-compose-portainer-root.target" ];
|
||||
wantedBy = [ "podman-compose-portainer-root.target" ];
|
||||
};
|
||||
|
||||
# Root service
|
||||
# When started, this will automatically create all resources and start
|
||||
# the containers. When stopped, this will teardown all resources.
|
||||
systemd.targets."podman-compose-portainer-root" = {
|
||||
unitConfig = { Description = "Root target generated by compose2nix."; };
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
};
|
||||
#+end_src
|
||||
|
||||
All that's left is to import these into this VM's configuration:
|
||||
|
||||
#+begin_src nix
|
||||
imports = [
|
||||
../virtualization/podman-utils.nix
|
||||
../virtualization/portainer.nix
|
||||
];
|
||||
#+end_src
|
||||
Loading…
Add table
Add a link
Reference in a new issue