feat: add a route to the traefik dashboard
This commit is contained in:
parent
2a761272a0
commit
5e21bf67e8
9 changed files with 106 additions and 22 deletions
|
@ -20,7 +20,6 @@ type DockerConfig struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// DockerNetworkConfig contains configuration for creating the docker network.
|
// DockerNetworkConfig contains configuration for creating the docker network.
|
||||||
|
|
||||||
type DockerNetworkConfig struct {
|
type DockerNetworkConfig struct {
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Subnet string `json:"subnet"`
|
Subnet string `json:"subnet"`
|
||||||
|
@ -41,10 +40,12 @@ type ServicesConfig struct {
|
||||||
// TraefikConfig contains configuration for the Traefik container.
|
// TraefikConfig contains configuration for the Traefik container.
|
||||||
type TraefikConfig struct {
|
type TraefikConfig struct {
|
||||||
CheckNewVersion bool `json:"checkNewVersion"`
|
CheckNewVersion bool `json:"checkNewVersion"`
|
||||||
|
ContainerIp string `json:"containerIp"`
|
||||||
|
Domain string `json:"domain"`
|
||||||
|
GroupId int
|
||||||
|
LogLevel string `json:"logLevel"`
|
||||||
SendAnonymousUsage bool `json:"sendAnonymousUsage"`
|
SendAnonymousUsage bool `json:"sendAnonymousUsage"`
|
||||||
Version string `json:"version"`
|
Version string `json:"version"`
|
||||||
ContainerIp string `json:"containerIp"`
|
|
||||||
LogLevel string `json:"logLevel"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewConfig creates a new Config value from a given
|
// NewConfig creates a new Config value from a given
|
||||||
|
|
|
@ -30,10 +30,11 @@ func TestValidConfig(t *testing.T) {
|
||||||
Services: ServicesConfig{
|
Services: ServicesConfig{
|
||||||
Traefik: TraefikConfig{
|
Traefik: TraefikConfig{
|
||||||
CheckNewVersion: true,
|
CheckNewVersion: true,
|
||||||
|
ContainerIp: "172.17.1.2",
|
||||||
|
Domain: "forge.localhost",
|
||||||
|
LogLevel: "info",
|
||||||
SendAnonymousUsage: false,
|
SendAnonymousUsage: false,
|
||||||
Version: "v2.4.9",
|
Version: "v2.4.9",
|
||||||
ContainerIp: "172.17.1.2",
|
|
||||||
LogLevel: "info",
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
3
internal/config/testdata/config-valid.json
vendored
3
internal/config/testdata/config-valid.json
vendored
|
@ -16,7 +16,8 @@
|
||||||
"sendAnonymousUsage": false,
|
"sendAnonymousUsage": false,
|
||||||
"version": "v2.4.9",
|
"version": "v2.4.9",
|
||||||
"containerIp": "172.17.1.2",
|
"containerIp": "172.17.1.2",
|
||||||
"logLevel": "info"
|
"logLevel": "info",
|
||||||
|
"domain": "forge.localhost"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,23 +10,32 @@ import (
|
||||||
// DockerContainerInput is the configuration
|
// DockerContainerInput is the configuration
|
||||||
// used to create the Gitea docker container.
|
// used to create the Gitea docker container.
|
||||||
type DockerContainerInput struct {
|
type DockerContainerInput struct {
|
||||||
Image pulumi.StringInput
|
Image pulumi.StringInput
|
||||||
Ipv4Address pulumi.StringInput
|
Ipv4Address pulumi.StringInput
|
||||||
EnvVars pulumi.StringArray
|
EnvVars pulumi.StringArray
|
||||||
Name pulumi.StringInput
|
Name pulumi.StringInput
|
||||||
Network pulumi.StringInput
|
Network pulumi.StringInput
|
||||||
Volumes []DockerVolumeMount
|
HostPathVolumes []HostPathVolume
|
||||||
UniqueLabel string
|
DockerVolumes []DockerVolume
|
||||||
|
UniqueLabel string
|
||||||
}
|
}
|
||||||
|
|
||||||
// DockerVolumeMount is the configuration
|
// HostPathVolume is the configuration
|
||||||
// used for mounting a host directory
|
// used for mounting a host directory
|
||||||
// to a directory inside a container.
|
// to a directory inside a container.
|
||||||
type DockerVolumeMount struct {
|
type HostPathVolume struct {
|
||||||
HostPath pulumi.StringInput
|
HostPath pulumi.StringInput
|
||||||
MountPath pulumi.StringInput
|
MountPath pulumi.StringInput
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DockerVolume is the configuration
|
||||||
|
// used for mounting a docker volume
|
||||||
|
// to a directory inside a container.
|
||||||
|
type DockerVolume struct {
|
||||||
|
Name pulumi.StringInput
|
||||||
|
MountPath pulumi.StringInput
|
||||||
|
}
|
||||||
|
|
||||||
func CreateContainer(ctx *pulumi.Context, c DockerContainerInput) error {
|
func CreateContainer(ctx *pulumi.Context, c DockerContainerInput) error {
|
||||||
// all containers will mount the host's timezone and localtime files
|
// all containers will mount the host's timezone and localtime files
|
||||||
// to ensure the correct time is synced.
|
// to ensure the correct time is synced.
|
||||||
|
@ -43,13 +52,21 @@ func CreateContainer(ctx *pulumi.Context, c DockerContainerInput) error {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
// optionally create additional container volumes.
|
// create additional container volumes if specified.
|
||||||
for _, v := range c.Volumes {
|
for _, v := range c.HostPathVolumes {
|
||||||
vArg := docker.ContainerVolumeArgs{
|
arg := docker.ContainerVolumeArgs{
|
||||||
ContainerPath: v.MountPath,
|
ContainerPath: v.MountPath,
|
||||||
HostPath: v.HostPath,
|
HostPath: v.HostPath,
|
||||||
}
|
}
|
||||||
volumes = append(volumes, vArg)
|
volumes = append(volumes, arg)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, v := range c.DockerVolumes {
|
||||||
|
arg := docker.ContainerVolumeArgs{
|
||||||
|
ContainerPath: v.MountPath,
|
||||||
|
VolumeName: v.Name,
|
||||||
|
}
|
||||||
|
volumes = append(volumes, arg)
|
||||||
}
|
}
|
||||||
|
|
||||||
args := docker.ContainerArgs{
|
args := docker.ContainerArgs{
|
||||||
|
|
|
@ -29,6 +29,12 @@ var templateTraefikDockerfile string
|
||||||
//go:embed templates/traefik/traefik.yaml.tmpl
|
//go:embed templates/traefik/traefik.yaml.tmpl
|
||||||
var templateTraefikStaticConfig string
|
var templateTraefikStaticConfig string
|
||||||
|
|
||||||
|
//go:embed templates/traefik/dynamic_dashboard.yaml.tmpl
|
||||||
|
var templateTraefikDynamicDashboardConfig string
|
||||||
|
|
||||||
|
//go:embed templates/traefik/entrypoint.sh.tmpl
|
||||||
|
var templateTraefikEntrypoint string
|
||||||
|
|
||||||
// newContainerStack creates the ContainerStack value.
|
// newContainerStack creates the ContainerStack value.
|
||||||
func newDockerStack(ctx context.Context, project, stack string, c config.Config) (*DockerStack, error) {
|
func newDockerStack(ctx context.Context, project, stack string, c config.Config) (*DockerStack, error) {
|
||||||
deployFunc := deployDockerStack(project, c.Docker, c.Services)
|
deployFunc := deployDockerStack(project, c.Docker, c.Services)
|
||||||
|
@ -79,6 +85,9 @@ func (c *DockerStack) Destroy(ctx context.Context) error {
|
||||||
// deployDockerStack returns a Pulumi run function
|
// deployDockerStack returns a Pulumi run function
|
||||||
// that is used to deploy the docker stack.
|
// that is used to deploy the docker stack.
|
||||||
func deployDockerStack(project string, dockerConfig config.DockerConfig, services config.ServicesConfig) pulumi.RunFunc {
|
func deployDockerStack(project string, dockerConfig config.DockerConfig, services config.ServicesConfig) pulumi.RunFunc {
|
||||||
|
groupID := 2239
|
||||||
|
services.Traefik.GroupId = groupID
|
||||||
|
|
||||||
return func(ctx *pulumi.Context) error {
|
return func(ctx *pulumi.Context) error {
|
||||||
// TODO: Create the provider when we start playing with remote hosts
|
// TODO: Create the provider when we start playing with remote hosts
|
||||||
|
|
||||||
|
@ -96,11 +105,11 @@ func deployDockerStack(project string, dockerConfig config.DockerConfig, service
|
||||||
|
|
||||||
// Create the shared volume
|
// Create the shared volume
|
||||||
sharedVolumeInput := docker.DockerVolumeInput{
|
sharedVolumeInput := docker.DockerVolumeInput{
|
||||||
Name: pulumi.String(dockerConfig.SharedVolume.Name),
|
Name: pulumi.String(dockerConfig.SharedVolume.Name),
|
||||||
UniqueLabel: "shared",
|
UniqueLabel: "shared",
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = docker.CreateVolume(ctx, sharedVolumeInput)
|
sharedVolume, err := docker.CreateVolume(ctx, sharedVolumeInput)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -125,6 +134,14 @@ func deployDockerStack(project string, dockerConfig config.DockerConfig, service
|
||||||
return fmt.Errorf("unable to generate the Traefik static configuration from template...\n%w", err)
|
return fmt.Errorf("unable to generate the Traefik static configuration from template...\n%w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := generateFile(services.Traefik, templateTraefikDynamicDashboardConfig, "traefikDashboardConf", filepath.Join(traefikContextDir, "dynamic_dashboard.yaml")); err != nil {
|
||||||
|
return fmt.Errorf("unable to generate the Traefik dashboard configuration from template...\n%w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := generateFile(services.Traefik, templateTraefikEntrypoint, "traefikEntrypoint", filepath.Join(traefikContextDir, "entrypoint.sh")); err != nil {
|
||||||
|
return fmt.Errorf("unable to generate the Traefik entrypoint script from template...\n%w", err)
|
||||||
|
}
|
||||||
|
|
||||||
c := docker.DockerImageInput{
|
c := docker.DockerImageInput{
|
||||||
BuildContext: pulumi.String(traefikContextDir),
|
BuildContext: pulumi.String(traefikContextDir),
|
||||||
Dockerfile: pulumi.String(filepath.Join(traefikContextDir, "Dockerfile")),
|
Dockerfile: pulumi.String(filepath.Join(traefikContextDir, "Dockerfile")),
|
||||||
|
@ -144,6 +161,12 @@ func deployDockerStack(project string, dockerConfig config.DockerConfig, service
|
||||||
Name: pulumi.String("helix-traefik"),
|
Name: pulumi.String("helix-traefik"),
|
||||||
Network: network.Name,
|
Network: network.Name,
|
||||||
UniqueLabel: "traefik-container",
|
UniqueLabel: "traefik-container",
|
||||||
|
DockerVolumes: []docker.DockerVolume{
|
||||||
|
{
|
||||||
|
Name: sharedVolume.Name,
|
||||||
|
MountPath: pulumi.String("/helix/shared"),
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = docker.CreateContainer(ctx, traefikContainerInput); err != nil {
|
if err = docker.CreateContainer(ctx, traefikContainerInput); err != nil {
|
||||||
|
|
|
@ -2,6 +2,12 @@ FROM traefik:{{ .Version }}
|
||||||
|
|
||||||
ADD traefik.yml /helix/traefik/
|
ADD traefik.yml /helix/traefik/
|
||||||
|
|
||||||
|
ADD entrypoint.sh /
|
||||||
|
|
||||||
|
ADD dynamic_dashboard.yaml /tmp/
|
||||||
|
|
||||||
|
RUN chmod +x /entrypoint.sh
|
||||||
|
|
||||||
EXPOSE 22 80 443
|
EXPOSE 22 80 443
|
||||||
|
|
||||||
CMD ["--configfile=/helix/traefik/traefik.yml"]
|
CMD ["--configfile=/helix/traefik/traefik.yml"]
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
---
|
||||||
|
http:
|
||||||
|
routers:
|
||||||
|
dashboard:
|
||||||
|
entryPoints:
|
||||||
|
- "https"
|
||||||
|
rule: "Host(`{{ .Domain }}`) && (PathPrefix(`/api`) || PathPrefix(`/dashboard`))"
|
||||||
|
service: "api@internal"
|
||||||
|
tls: {}
|
26
internal/stacks/templates/traefik/entrypoint.sh.tmpl
Normal file
26
internal/stacks/templates/traefik/entrypoint.sh.tmpl
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
#!/bin/sh
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# Create the dynamic config directory in the shared volume.
|
||||||
|
mkdir -p /helix/shared/traefik/dynamic
|
||||||
|
chgrp {{ .GroupId }} /helix/shared/traefik/dynamic
|
||||||
|
chmod a-rwx,u+rwx,g+rwx /helix/shared/traefik/dynamic
|
||||||
|
|
||||||
|
# Move the dashboard config to the new directory.
|
||||||
|
mv /tmp/dynamic_dashboard.yaml /helix/shared/traefik/dynamic/dashboard.yaml
|
||||||
|
|
||||||
|
# first arg is `-f` or `--some-option`
|
||||||
|
if [ "${1#-}" != "$1" ]; then
|
||||||
|
set -- traefik "$@"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# if our command is a valid Traefik subcommand, let's invoke it through Traefik instead
|
||||||
|
# (this allows for "docker run traefik version", etc)
|
||||||
|
if traefik "$1" --help >/dev/null 2>&1
|
||||||
|
then
|
||||||
|
set -- traefik "$@"
|
||||||
|
else
|
||||||
|
echo "= '$1' is not a Traefik command: assuming shell execution." 1>&2
|
||||||
|
fi
|
||||||
|
|
||||||
|
exec "$@"
|
|
@ -22,6 +22,6 @@ entryPoints:
|
||||||
providers:
|
providers:
|
||||||
file:
|
file:
|
||||||
watch: true
|
watch: true
|
||||||
directory: "/helix/traefik/config/dynamic"
|
directory: "/helix/shared/traefik/dynamic"
|
||||||
log:
|
log:
|
||||||
level: "{{ .LogLevel }}"
|
level: "{{ .LogLevel }}"
|
||||||
|
|
Reference in a new issue