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 ¶
- Variables
- type Builder
- type Commit
- type Config
- type Deployer
- func (d *Deployer) ApplyRoutes(ctx context.Context) error
- func (d *Deployer) AvailableImages(ctx context.Context, serviceID string, images []string) (map[string]bool, error)
- func (d *Deployer) BuildLog(ctx context.Context, deploymentID string, n int) ([]string, error)
- func (d *Deployer) Cancel(ctx context.Context, deploymentID string) (store.Deployment, error)
- func (d *Deployer) ClearRestoreFence(ctx context.Context, serviceID string) error
- func (d *Deployer) DeleteProject(ctx context.Context, projectID string) error
- func (d *Deployer) DeleteService(ctx context.Context, serviceID string) error
- func (d *Deployer) DeleteVolume(ctx context.Context, volumeID string) error
- func (d *Deployer) Deploy(ctx context.Context, serviceID string, trigger store.Trigger, c Commit) (store.Deployment, error)
- func (d *Deployer) FollowLog(ctx context.Context, deploymentID string, line func(string), ...) error
- func (d *Deployer) Hold(ctx context.Context, serviceID string) (*Held, error)
- func (d *Deployer) Reconcile(ctx context.Context) error
- func (d *Deployer) Redeploy(ctx context.Context, deploymentID string) (store.Deployment, error)
- func (d *Deployer) ResolveVariables(ctx context.Context, serviceID string) (Resolved, error)
- func (d *Deployer) RestartService(ctx context.Context, serviceID string) error
- func (d *Deployer) RuntimeLogs(ctx context.Context, serviceID string, tail int, follow bool, w io.Writer) error
- func (d *Deployer) ServiceStatuses(ctx context.Context, projectID string) (map[string]ServiceStatus, error)
- func (d *Deployer) StartService(ctx context.Context, serviceID string) error
- func (d *Deployer) Stop()
- func (d *Deployer) StopService(ctx context.Context, serviceID string) error
- type Docker
- type GitHub
- type Held
- type OnePassword
- type Proxy
- type Resolved
- type ServiceStatus
Constants ¶
This section is empty.
Variables ¶
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") )
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 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 ¶
New returns a Deployer. Call Reconcile once before serving requests and Stop on shutdown.
func (*Deployer) ApplyRoutes ¶
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 ¶
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 ¶
Cancel cancels a deployment that is in progress and returns it. It returns ErrNotInProgress if the deployment has already finished.
func (*Deployer) ClearRestoreFence ¶
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 ¶
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 ¶
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 ¶
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 ¶
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 ¶
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 ¶
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 ¶
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 ¶
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 ¶
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 ¶
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 ¶
Active returns the service's active deployment, or store.ErrNotFound if it has none.
func (*Held) Release ¶
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) StopAndRemove ¶
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 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.