better docker/podman/etc isntall

60c9058 · gmorell · 2026-05-22 03:02

1 files +187 -6

Files changed

modified lib/git_gud_web/components/core_components.ex
+187 −6
@@ -590,7 +590,8 @@ defmodule GitGudWeb.CoreComponents do
590 590
591 591 @doc """
592 592 Renders a tabbed block of `forgejo-runner register` + daemon command
593 snippets for native binary, Docker, and Podman.
593 + snippets for native binary, Docker, Podman, Podman Quadlet, and
594 + Kubernetes.
594 595
595 596 Use on runner settings pages right after a new token is minted
596 597 pass the bare token + the instance URL.
@@ -614,13 +615,22 @@ defmodule GitGudWeb.CoreComponents do
614 615 |> assign(:native_cmd, native_register_cmd(assigns))
615 616 |> assign(:docker_cmd, docker_register_cmd(assigns))
616 617 |> assign(:podman_cmd, podman_register_cmd(assigns))
618 + |> assign(:quadlet_cmd, quadlet_register_cmd(assigns))
619 + |> assign(:k8s_cmd, kubernetes_register_cmd(assigns))
617 620
618 621 ~H"""
619 622 <div role="tablist" class="tabs tabs-bordered">
620 623 <input type="radio" name={@tabs_name} role="tab" class="tab" aria-label="Native" checked />
621 624 <div role="tabpanel" class="tab-content p-3 space-y-2">
622 625 <p class="text-xs opacity-70">
623 Run on a host with <code>forgejo-runner</code> on $PATH.
626 + Run on a host with <code>forgejo-runner</code> on $PATH. See the
627 + <a
628 + class="link"
629 + href="https://forgejo.org/docs/latest/admin/actions/installation/binary/"
630 + target="_blank"
631 + rel="noopener"
632 + >binary install docs</a>
633 + for the systemd unit.
624 634 </p>
625 635 <pre class="text-xs bg-base-200 p-3 rounded overflow-x-auto" phx-no-curly-interpolation><%= @native_cmd %></pre>
626 636 </div>
@@ -629,6 +639,13 @@ defmodule GitGudWeb.CoreComponents do
629 639 <div role="tabpanel" class="tab-content p-3 space-y-2">
630 640 <p class="text-xs opacity-70">
631 641 Mounts the host's Docker socket so the runner can spawn job containers.
642 + For a dind-isolated <code>docker compose</code> variant, see the
643 + <a
644 + class="link"
645 + href="https://forgejo.org/docs/latest/admin/actions/installation/docker/"
646 + target="_blank"
647 + rel="noopener"
648 + >Docker install docs</a>.
632 649 </p>
633 650 <pre class="text-xs bg-base-200 p-3 rounded overflow-x-auto" phx-no-curly-interpolation><%= @docker_cmd %></pre>
634 651 </div>
@@ -637,10 +654,31 @@ defmodule GitGudWeb.CoreComponents do
637 654 <div role="tabpanel" class="tab-content p-3 space-y-2">
638 655 <p class="text-xs opacity-70">
639 656 Rootless Podman. Enable user lingering (<code>loginctl enable-linger &lt;user&gt;</code>)
640 and ensure the Podman socket is reachable at <code>$XDG_RUNTIME_DIR/podman/podman.sock</code>.
657 + and ensure the Podman socket is reachable at <code>$XDG_RUNTIME_DIR/podman/podman.sock</code>
658 + (start it with <code>systemctl --user enable --now podman.socket</code>).
641 659 </p>
642 660 <pre class="text-xs bg-base-200 p-3 rounded overflow-x-auto" phx-no-curly-interpolation><%= @podman_cmd %></pre>
643 661 </div>
662 +
663 + <input type="radio" name={@tabs_name} role="tab" class="tab" aria-label="Quadlet" />
664 + <div role="tabpanel" class="tab-content p-3 space-y-2">
665 + <p class="text-xs opacity-70">
666 + Podman Quadlet (<code>systemd</code>-managed rootless container).
667 + Drop the <code>.container</code> file in
668 + <code>~/.config/containers/systemd/</code> and reload the user units.
669 + </p>
670 + <pre class="text-xs bg-base-200 p-3 rounded overflow-x-auto" phx-no-curly-interpolation><%= @quadlet_cmd %></pre>
671 + </div>
672 +
673 + <input type="radio" name={@tabs_name} role="tab" class="tab" aria-label="Kubernetes" />
674 + <div role="tabpanel" class="tab-content p-3 space-y-2">
675 + <p class="text-xs opacity-70">
676 + Deployment + dind sidecar. The init container registers on first
677 + start; the daemon then talks to <code>docker:dind</code> over
678 + localhost. Apply with <code>kubectl apply -f forgejo-runner.yaml</code>.
679 + </p>
680 + <pre class="text-xs bg-base-200 p-3 rounded overflow-x-auto" phx-no-curly-interpolation><%= @k8s_cmd %></pre>
681 + </div>
644 682 </div>
645 683 """
646 684 end
@@ -648,13 +686,15 @@ defmodule GitGudWeb.CoreComponents do
648 686 defp native_register_cmd(%{instance_url: url, token: token, runner_name: name}) do
649 687 Enum.join(
650 688 [
689 + "forgejo-runner generate-config > runner-config.yml",
690 + "",
651 691 "forgejo-runner register \\",
652 692 " --instance #{url} \\",
653 693 " --token #{token} \\",
654 694 " --name #{name} \\",
655 695 " --no-interactive",
656 696 "",
657 "forgejo-runner daemon"
697 + "forgejo-runner daemon --config runner-config.yml"
658 698 ],
659 699 "\n"
660 700 )
@@ -669,6 +709,9 @@ defmodule GitGudWeb.CoreComponents do
669 709 [
670 710 "mkdir -p ./runner-data && cd ./runner-data",
671 711 "",
712 + "docker run --rm #{image} \\",
713 + " forgejo-runner generate-config > runner-config.yml",
714 + "",
672 715 "docker run --rm \\",
673 716 " --user $(id -u):$(id -g) \\",
674 717 " -v $(pwd):/data \\",
@@ -685,7 +728,7 @@ defmodule GitGudWeb.CoreComponents do
685 728 " -v $(pwd):/data \\",
686 729 " -v /var/run/docker.sock:/var/run/docker.sock \\",
687 730 " #{image} \\",
688 " daemon"
731 + " forgejo-runner daemon --config /data/runner-config.yml"
689 732 ],
690 733 "\n"
691 734 )
@@ -700,6 +743,9 @@ defmodule GitGudWeb.CoreComponents do
700 743 [
701 744 "mkdir -p ./runner-data && cd ./runner-data",
702 745 "",
746 + "podman run --rm #{image} \\",
747 + " forgejo-runner generate-config > runner-config.yml",
748 + "",
703 749 "podman run --rm \\",
704 750 " --userns=keep-id \\",
705 751 " --security-opt label=disable \\",
@@ -718,7 +764,142 @@ defmodule GitGudWeb.CoreComponents do
718 764 " -v $(pwd):/data \\",
719 765 " -v $XDG_RUNTIME_DIR/podman/podman.sock:/var/run/docker.sock \\",
720 766 " #{image} \\",
721 " daemon"
767 + " forgejo-runner daemon --config /data/runner-config.yml"
768 + ],
769 + "\n"
770 + )
771 + end
772 +
773 + defp quadlet_register_cmd(%{instance_url: url, token: token, runner_name: name, image: image}) do
774 + # Quadlets are read by `podman-system-generator` out of
775 + # `~/.config/containers/systemd/` (rootless) and managed as user
776 + # systemd units. The `Exec=` line maps to the container's CMD.
777 + Enum.join(
778 + [
779 + "# One-time bootstrap: generate config + register",
780 + "mkdir -p ~/.local/share/forgejo-runner && cd ~/.local/share/forgejo-runner",
781 + "",
782 + "podman run --rm #{image} \\",
783 + " forgejo-runner generate-config > runner-config.yml",
784 + "",
785 + "podman run --rm \\",
786 + " --userns=keep-id \\",
787 + " --security-opt label=disable \\",
788 + " -v $(pwd):/data \\",
789 + " #{image} \\",
790 + " forgejo-runner register \\",
791 + " --instance #{url} \\",
792 + " --token #{token} \\",
793 + " --name #{name} \\",
794 + " --no-interactive",
795 + "",
796 + "# Drop this into ~/.config/containers/systemd/forgejo-runner.container",
797 + "cat > ~/.config/containers/systemd/forgejo-runner.container <<'EOF'",
798 + "[Unit]",
799 + "Description=Forgejo Runner",
800 + "After=network-online.target",
801 + "Wants=network-online.target",
802 + "",
803 + "[Container]",
804 + "Image=#{image}",
805 + "ContainerName=forgejo-runner",
806 + "UserNS=keep-id",
807 + "SecurityLabelDisable=true",
808 + "Volume=%h/.local/share/forgejo-runner:/data:Z",
809 + "Volume=%t/podman/podman.sock:/var/run/docker.sock",
810 + "Exec=forgejo-runner daemon --config /data/runner-config.yml",
811 + "",
812 + "[Service]",
813 + "Restart=always",
814 + "",
815 + "[Install]",
816 + "WantedBy=default.target",
817 + "EOF",
818 + "",
819 + "systemctl --user daemon-reload",
820 + "systemctl --user start forgejo-runner.service",
821 + "loginctl enable-linger \"$USER\" # survive logout"
822 + ],
823 + "\n"
824 + )
825 + end
826 +
827 + defp kubernetes_register_cmd(%{
828 + instance_url: url,
829 + token: token,
830 + runner_name: name,
831 + image: image
832 + }) do
833 + # The init container performs `forgejo-runner register` against a
834 + # shared emptyDir; the main container then starts the daemon and
835 + # picks up `.runner` from that same volume. `docker:dind` runs as a
836 + # sidecar so we don't expose the node's container runtime.
837 + Enum.join(
838 + [
839 + "# Save as forgejo-runner.yaml, then: kubectl apply -f forgejo-runner.yaml",
840 + "apiVersion: v1",
841 + "kind: Namespace",
842 + "metadata:",
843 + " name: forgejo-runner",
844 + "---",
845 + "apiVersion: v1",
846 + "kind: Secret",
847 + "metadata:",
848 + " name: forgejo-runner-token",
849 + " namespace: forgejo-runner",
850 + "type: Opaque",
851 + "stringData:",
852 + " token: #{token}",
853 + "---",
854 + "apiVersion: apps/v1",
855 + "kind: Deployment",
856 + "metadata:",
857 + " name: forgejo-runner",
858 + " namespace: forgejo-runner",
859 + "spec:",
860 + " replicas: 1",
861 + " selector:",
862 + " matchLabels: { app: forgejo-runner }",
863 + " template:",
864 + " metadata:",
865 + " labels: { app: forgejo-runner }",
866 + " spec:",
867 + " initContainers:",
868 + " - name: register",
869 + " image: #{image}",
870 + " command: [\"sh\", \"-c\"]",
871 + " args:",
872 + " - |",
873 + " set -e",
874 + " cd /data",
875 + " [ -f runner-config.yml ] || forgejo-runner generate-config > runner-config.yml",
876 + " [ -f .runner ] || forgejo-runner register \\",
877 + " --instance #{url} \\",
878 + " --token \"$RUNNER_TOKEN\" \\",
879 + " --name #{name} \\",
880 + " --no-interactive",
881 + " env:",
882 + " - name: RUNNER_TOKEN",
883 + " valueFrom:",
884 + " secretKeyRef: { name: forgejo-runner-token, key: token }",
885 + " volumeMounts:",
886 + " - { name: data, mountPath: /data }",
887 + " containers:",
888 + " - name: runner",
889 + " image: #{image}",
890 + " command: [\"forgejo-runner\", \"daemon\", \"--config\", \"/data/runner-config.yml\"]",
891 + " workingDir: /data",
892 + " env:",
893 + " - { name: DOCKER_HOST, value: \"tcp://localhost:2375\" }",
894 + " volumeMounts:",
895 + " - { name: data, mountPath: /data }",
896 + " - name: dind",
897 + " image: docker:dind",
898 + " args: [\"dockerd\", \"-H\", \"tcp://0.0.0.0:2375\", \"--tls=false\"]",
899 + " securityContext: { privileged: true }",
900 + " volumes:",
901 + " - name: data",
902 + " emptyDir: {}"
722 903 ],
723 904 "\n"
724 905 )

Parents: 5c83970