mirror of
https://github.com/psviderski/uncloud.git
synced 2026-08-26 11:03:34 +00:00
119 lines
3.0 KiB
Go
119 lines
3.0 KiB
Go
package client
|
|
|
|
import (
|
|
"fmt"
|
|
"regexp"
|
|
|
|
"github.com/Masterminds/semver"
|
|
"github.com/distribution/reference"
|
|
"github.com/google/go-containerregistry/pkg/name"
|
|
"github.com/google/go-containerregistry/pkg/v1/remote"
|
|
"github.com/psviderski/uncloud/pkg/api"
|
|
"github.com/psviderski/uncloud/pkg/client/deploy"
|
|
)
|
|
|
|
const (
|
|
CaddyServiceName = "caddy"
|
|
// CaddyImage is the official Caddy Docker image on Docker Hub: https://hub.docker.com/_/caddy
|
|
CaddyImage = "caddy"
|
|
)
|
|
|
|
var caddyImageTagRegex = regexp.MustCompile(`^2\.\d+\.\d+$`)
|
|
|
|
// NewCaddyDeployment creates a new deployment for a Caddy reverse proxy service.
|
|
// The service is deployed in global mode to all machines in the cluster. If the image is not provided, the latest
|
|
// version of the official Caddy Docker image is used.
|
|
func (cli *Client) NewCaddyDeployment(image string, placement api.Placement) (*deploy.Deployment, error) {
|
|
if image == "" {
|
|
latest, err := LatestCaddyImage()
|
|
if err != nil {
|
|
return nil, fmt.Errorf("look up latest Caddy image: %w", err)
|
|
}
|
|
|
|
image = reference.FamiliarString(latest)
|
|
}
|
|
|
|
spec := api.ServiceSpec{
|
|
Container: api.ContainerSpec{
|
|
Command: []string{"caddy", "run", "-c", "/config/caddy.json", "--watch"},
|
|
Image: image,
|
|
VolumeMounts: []api.VolumeMount{
|
|
{
|
|
VolumeName: "config",
|
|
ContainerPath: "/config",
|
|
},
|
|
},
|
|
},
|
|
Mode: api.ServiceModeGlobal,
|
|
Name: CaddyServiceName,
|
|
Placement: placement,
|
|
Ports: []api.PortSpec{
|
|
{
|
|
PublishedPort: 80,
|
|
ContainerPort: 80,
|
|
Protocol: api.ProtocolTCP,
|
|
Mode: api.PortModeHost,
|
|
},
|
|
{
|
|
PublishedPort: 443,
|
|
ContainerPort: 443,
|
|
Protocol: api.ProtocolTCP,
|
|
Mode: api.PortModeHost,
|
|
},
|
|
},
|
|
Volumes: []api.VolumeSpec{
|
|
{
|
|
Name: "config",
|
|
Type: api.VolumeTypeBind,
|
|
BindOptions: &api.BindOptions{
|
|
HostPath: "/var/lib/uncloud/caddy",
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
return cli.NewDeployment(spec, nil), nil
|
|
}
|
|
|
|
// LatestCaddyImage returns the latest image of the official Caddy Docker image on Docker Hub.
|
|
// The latest image is determined by the latest version tag 2.x.x.
|
|
func LatestCaddyImage() (reference.NamedTagged, error) {
|
|
repo, err := name.NewRepository(CaddyImage)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("parse image: %w", err)
|
|
}
|
|
tags, err := remote.List(repo)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("list image tags: %w", err)
|
|
}
|
|
|
|
// Default to the 'latest' tag but try to find the latest version tag 2.x.x.
|
|
latestTag := "latest"
|
|
var latestVersion *semver.Version
|
|
for _, t := range tags {
|
|
if !caddyImageTagRegex.MatchString(t) {
|
|
continue
|
|
}
|
|
|
|
v, err := semver.NewVersion(t)
|
|
if err != nil {
|
|
continue
|
|
}
|
|
if latestVersion == nil || v.GreaterThan(latestVersion) {
|
|
latestVersion = v
|
|
latestTag = t
|
|
}
|
|
}
|
|
|
|
image, err := reference.ParseDockerRef(CaddyImage)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("parse image: %w", err)
|
|
}
|
|
imageWithTag, err := reference.WithTag(image, latestTag)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("set image tag: %w", err)
|
|
}
|
|
|
|
return imageWithTag, nil
|
|
}
|