Help us shape the future of Go! Take the 2026 Go Developer Survey

deploy

package
v0.2.4 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 23, 2026 License: Apache-2.0 Imports: 26 Imported by: 0

Documentation

Overview

Package deploy runs shed's deployment pipeline.

A Deployer turns deployments into running containers: it waits for CI, builds or pulls the image, resolves variables, starts the container, checks its health, switches the proxy routes, and retires the previous container. Each service has its own queue, and a newer deployment cancels older ones that are still in progress. The Deployer also reconciles state on boot, stops, starts, and restarts services, tears services and projects down, and derives service status.

Docker, the image builder, the proxy, and GitHub are reached through small interfaces so they can be replaced, for example by fakes in tests.

Index

Constants

This section is empty.

Variables

View Source
var (
	// ErrDeleting is returned while a service or its project is being deleted.
	ErrDeleting = errors.New("deploy: service is being deleted")
	// ErrStopped is returned for deployments requested after Stop.
	ErrStopped = errors.New("deploy: deployer is stopped")
	// ErrNotInProgress is returned when canceling a finished deployment.
	ErrNotInProgress = errors.New("deploy: deployment is not in progress")
	// ErrNoImage is returned when redeploying a deployment that has no image.
	ErrNoImage = errors.New("deploy: deployment has no image to redeploy")
	// ErrNoContainer is returned for runtime logs of a service that has no
	// active container, and when starting or restarting such a service.
	ErrNoContainer = errors.New("deploy: service has no active container")
	// ErrServiceStopped is returned when restarting a stopped service.
	ErrServiceStopped = errors.New("deploy: service is stopped")
	// ErrServiceBusy is returned while a service is held for a backup or
	// restore.
	ErrServiceBusy = errors.New("deploy: service is busy with a backup or restore")
	// ErrFenced is returned when deploying, redeploying, starting, or
	// restarting a service that a failed restore left fenced, because its
	// data may be partial. ClearRestoreFence lifts the refusal.
	ErrFenced = errors.New("deploy: service is fenced by a failed restore")
	// ErrVolumeMissing is returned when the container of an active
	// deployment must be recreated but a volume it mounted is gone from
	// Docker, such as on a new host. Its data is not recreated empty; a new
	// deployment or a restore does that explicitly.
	ErrVolumeMissing = errors.New("deploy: a volume of the deployment is missing on this host")
)
View Source
var ErrImageUnavailable = errors.New("deploy: deployment's image is no longer on this host")

ErrImageUnavailable is returned when a deployment's image is no longer on this host, such as after old images were pruned or on a new host, so its container cannot be run without building or pulling it again.

Functions

This section is empty.

Types

type Builder

type Builder interface {
	Build(ctx context.Context, id string, req build.Request, out io.Writer) error
}

Builder builds images from source. *build.Builder implements it.

type Commit

type Commit struct {
	SHA     string
	Message string
	Author  string
}

Commit identifies the source revision of a deployment.

type Config

type Config struct {
	Store   *store.Store
	Docker  Docker
	Builder Builder
	// Proxy receives the routes after every change. Nil disables routing.
	Proxy Proxy
	// GitHub returns the GitHub client, or false while the GitHub App is not
	// configured.
	GitHub func() (GitHub, bool)
	// OnePassword reads the 1Password Environments services link. Nil fails
	// deployments of services that link one.
	OnePassword OnePassword
	// LogDir holds the build logs, one <deploymentID>.log per deployment.
	LogDir string
	// LogLimit caps each build log, in bytes. Output beyond it is replaced
	// by a truncation notice. Zero means unlimited.
	LogLimit int64
	// KeepDeployments is how many deployments of each service are kept after
	// a deployment ends. Older finished ones are deleted along with their
	// build logs. Zero keeps them all.
	KeepDeployments int
	// Dashboard, if its Host is set, is included in every route set.
	Dashboard proxy.Route
	Log       *slog.Logger
}

Config configures a Deployer.

type Deployer

type Deployer struct {
	// contains filtered or unexported fields
}

Deployer runs deployments. It is safe for concurrent use.

func New

func New(cfg Config) *Deployer

New returns a Deployer. Call Reconcile once before serving requests and Stop on shutdown.

func (*Deployer) ApplyRoutes

func (d *Deployer) ApplyRoutes(ctx context.Context) error

ApplyRoutes points the proxy at the active container of every running service with a domain, plus the dashboard. Call it after anything that changes domains or active deployments.

func (*Deployer) AvailableImages

func (d *Deployer) AvailableImages(ctx context.Context, serviceID string, images []string) (map[string]bool, error)

AvailableImages reports which of images, the images of a service's deployments, are on this host, and so can be redeployed.

func (*Deployer) BuildLog

func (d *Deployer) BuildLog(ctx context.Context, deploymentID string, n int) ([]string, error)

BuildLog returns the last n lines of a deployment's build log, for showing outside the dashboard. The log was masked as it was written; BuildLog also masks the values given by maskedValues, which covers values saved since. Lines longer than 64 KiB are split.

func (*Deployer) Cancel

func (d *Deployer) Cancel(ctx context.Context, deploymentID string) (store.Deployment, error)

Cancel cancels a deployment that is in progress and returns it. It returns ErrNotInProgress if the deployment has already finished.

func (*Deployer) ClearRestoreFence

func (d *Deployer) ClearRestoreFence(ctx context.Context, serviceID string) error

ClearRestoreFence removes the fence that a failed restore left on a service, keeping the data the service has now. The service stays stopped until it is started or deployed. A service without a fence is left as it is. It returns ErrServiceBusy while the service is held, such as during a restore.

func (*Deployer) DeleteProject

func (d *Deployer) DeleteProject(ctx context.Context, projectID string) error

DeleteProject deletes every service of a project as DeleteService does, then its network, then the project itself. It returns ErrServiceBusy while any of its services is held.

func (*Deployer) DeleteService

func (d *Deployer) DeleteService(ctx context.Context, serviceID string) error

DeleteService stops a service's deployments, removes its containers, volumes, images, and build logs, and deletes it from the store. It returns ErrServiceBusy while the service is held.

func (*Deployer) DeleteVolume

func (d *Deployer) DeleteVolume(ctx context.Context, volumeID string) error

DeleteVolume deletes a volume and its data. A volume still mounted by the running container is detached by the service's next deployment, which then removes its data. It returns ErrServiceBusy while the service is held.

func (*Deployer) Deploy

func (d *Deployer) Deploy(ctx context.Context, serviceID string, trigger store.Trigger, c Commit) (store.Deployment, error)

Deploy queues a new deployment of a service and returns it. Older deployments of the service that are still in progress are canceled. It returns ErrFenced while the service is fenced by a failed restore.

func (*Deployer) FollowLog

func (d *Deployer) FollowLog(ctx context.Context, deploymentID string, line func(string), status func(store.DeploymentStatus)) error

FollowLog replays the build log of a deployment and follows it while the deployment is in progress. It calls line for every log line, and status with the current status and then whenever it changes. It returns nil once the deployment has finished and its log has been read, or the error of ctx if ctx ends first.

func (*Deployer) Hold

func (d *Deployer) Hold(ctx context.Context, serviceID string) (*Held, error)

Hold takes exclusive control of a service for a backup or restore. Deployments in progress are canceled, and until Release, deploying, redeploying, starting, stopping, restarting, or deleting the service, deleting one of its volumes, and deleting its project return ErrServiceBusy. Holding a service that is already held returns ErrServiceBusy, and holding one that is being deleted returns ErrDeleting.

func (*Deployer) Reconcile

func (d *Deployer) Reconcile(ctx context.Context) error

Reconcile brings Docker in line with the store after a restart: deployments that were in progress are marked failed, the active deployment's container of every service that is neither stopped nor fenced is started (or recreated if it is gone and its image and volumes are still on the host), and routes are applied. A service that cannot be started is logged and left crashed. It does not respect holds, so it must finish before anything calls Hold.

func (*Deployer) Redeploy

func (d *Deployer) Redeploy(ctx context.Context, deploymentID string) (store.Deployment, error)

Redeploy queues a new deployment that runs the image of an earlier one, skipping CI and the build. It is how rollbacks work. It returns ErrNoImage if the deployment has no image to reuse, and ErrImageUnavailable if its image is no longer on this host.

func (*Deployer) ResolveVariables

func (d *Deployer) ResolveVariables(ctx context.Context, serviceID string) (Resolved, error)

ResolveVariables returns the variables of a service with references expanded, as its next deployment would see them, reading 1Password Environments. SHED_GIT_COMMIT_SHA is the commit of the active deployment, if any.

func (*Deployer) RestartService

func (d *Deployer) RestartService(ctx context.Context, serviceID string) error

RestartService restarts the active deployment's container of a service. It returns ErrServiceStopped if the service is stopped, ErrNoContainer if it has no active container, ErrServiceBusy while it is held, and ErrFenced while it is fenced.

func (*Deployer) RuntimeLogs

func (d *Deployer) RuntimeLogs(ctx context.Context, serviceID string, tail int, follow bool, w io.Writer) error

RuntimeLogs writes the last tail lines of the output of a service's active container to w. With follow, it then follows the output until ctx ends or the container stops. The values of the variables the container was started with are masked, not those saved since. It returns ErrNoContainer if the service has no active container.

func (*Deployer) ServiceStatuses

func (d *Deployer) ServiceStatuses(ctx context.Context, projectID string) (map[string]ServiceStatus, error)

ServiceStatuses returns the status of every service of a project, keyed by service ID. A service is deploying while its latest deployment is in progress; otherwise stopped if the user stopped it; otherwise active or crashed depending on whether its active deployment's container is running; otherwise failed if its latest deployment failed; otherwise offline.

func (*Deployer) StartService

func (d *Deployer) StartService(ctx context.Context, serviceID string) error

StartService starts the active deployment's container of a stopped service, recreating it if it is gone, and routes its domains to it again. It returns ErrNoContainer if the service has no active deployment, ErrServiceBusy while it is held, ErrFenced while it is fenced, and ErrImageUnavailable if the container is gone and so is its image.

func (*Deployer) Stop

func (d *Deployer) Stop()

Stop cancels running deployments and waits for the workers to exit. Deployments still queued stay queued; Reconcile fails them on the next boot.

func (*Deployer) StopService

func (d *Deployer) StopService(ctx context.Context, serviceID string) error

StopService stops a service: deployments in progress are canceled, the active deployment's container is stopped but kept, and the service's domains stop routing. The active deployment stays active, so StartService or the next deployment brings the service back. It returns ErrServiceBusy while the service is held.

type Docker

type Docker interface {
	EnsureNetwork(ctx context.Context, name string) error
	RemoveNetwork(ctx context.Context, name string) error
	ReconnectNetwork(ctx context.Context, name, id string, aliases []string) error
	DisconnectNetwork(ctx context.Context, name, id string) error
	EnsureVolume(ctx context.Context, name string) error
	VolumeExists(ctx context.Context, name string) (bool, error)
	RemoveVolume(ctx context.Context, name string) error
	PullImage(ctx context.Context, ref string, w io.Writer) error
	ResolveImage(ctx context.Context, ref string) (string, error)
	ListImages(ctx context.Context, repo string) ([]docker.Image, error)
	ExposedPorts(ctx context.Context, ref string) ([]int, error)
	RemoveImage(ctx context.Context, ref string) error
	Run(ctx context.Context, spec docker.RunSpec) (string, error)
	Start(ctx context.Context, id string) error
	Stop(ctx context.Context, id string, timeout time.Duration) error
	Restart(ctx context.Context, id string, timeout time.Duration) error
	Remove(ctx context.Context, id string) error
	Inspect(ctx context.Context, id string) (docker.Container, error)
	List(ctx context.Context, labels map[string]string) ([]docker.Container, error)
	Logs(ctx context.Context, id string, tail int, follow bool, w io.Writer) error
}

Docker runs containers. *docker.Client implements it.

type GitHub

type GitHub interface {
	CloneURL(ctx context.Context, repo string) (string, error)
	CIStatus(ctx context.Context, repo, sha string) (github.CIState, error)
}

GitHub provides repository access and CI status. *github.Client implements it.

type Held

type Held struct {
	// contains filtered or unexported fields
}

Held is a service under Hold. It is safe for concurrent use.

func (*Held) Active

func (h *Held) Active(ctx context.Context) (store.Deployment, error)

Active returns the service's active deployment, or store.ErrNotFound if it has none.

func (*Held) Release

func (h *Held) Release(ctx context.Context) error

Release lifts the hold. Unless the user stopped the service, the active deployment's container is started first, recreated if it was removed; then routes are applied. The hold is lifted even if starting fails, and the error is returned. Release is not canceled with ctx, so a canceled restore still brings the service back. Calls after the first do nothing.

func (*Held) Running

func (h *Held) Running(ctx context.Context) (bool, error)

Running reports whether the active deployment's container is running.

func (*Held) StopAndRemove

func (h *Held) StopAndRemove(ctx context.Context) error

StopAndRemove stops and removes every container of the service, so its volumes can be removed and recreated. The active deployment stays active without a container, and its domains stop routing. Release starts it again.

type OnePassword added in v0.2.4

type OnePassword interface {
	Variables(ctx context.Context, environmentID string) (map[string]string, error)
}

OnePassword reads 1Password Environments. *onepassword.Client implements it.

type Proxy

type Proxy interface {
	Apply(routes []proxy.Route) error
}

Proxy routes public traffic. *proxy.Proxy implements it.

type Resolved added in v0.2.4

type Resolved struct {
	Env map[string]string
	// OnePassword holds the keys of Env whose value comes from the service's
	// 1Password Environment, sorted.
	OnePassword []string
}

Resolved holds the variables of a service with references expanded.

type ServiceStatus

type ServiceStatus string

ServiceStatus is the derived state of a service.

const (
	StatusOffline   ServiceStatus = "offline"
	StatusDeploying ServiceStatus = "deploying"
	StatusActive    ServiceStatus = "active"
	StatusFailed    ServiceStatus = "failed"
	StatusCrashed   ServiceStatus = "crashed"
	StatusStopped   ServiceStatus = "stopped"
)

Service statuses.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL