Skip to content

Commit fe2048c

Browse files
committed
Allow setting architecture of containers
Support creating containers of multi-platform images for an architecture other than that of the host running Complement.
1 parent 55095cf commit fe2048c

File tree

5 files changed

+52
-8
lines changed

5 files changed

+52
-8
lines changed

ENVIRONMENT.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,15 @@ If 1, always prints the Homeserver container logs even on success. When used wit
1616
This allows you to override the base image used for a particular named homeserver. For example, `COMPLEMENT_BASE_IMAGE_HS1=complement-dendrite:latest` would use `complement-dendrite:latest` for the `hs1` homeserver in blueprints, but not any other homeserver (e.g `hs2`). This matching is case-insensitive. This allows Complement to test how different homeserver implementations work with each other.
1717
- Type: `map[string]string`
1818

19+
#### `COMPLEMENT_BASE_ARCH`
20+
This allows you to override the architecture of the Docker image to use as a base homeserver when generating blueprints. This can be used to emulate a particular architecture with a multi-platform image. If "", the architecture of the host running Complement is used.
21+
- Type: `string`
22+
- Default: ""
23+
24+
#### `COMPLEMENT_BASE_ARCH_*`
25+
This allows you to set the architecture of the base image used for a particular named homeserver. For example, `COMPLEMENT_BASE_ARCH_HS1=arm64` would use an `arm64` for the `hs1` homeserver in blueprints, but not any other homeserver (e.g `hs2`). This matching is case-insensitive.
26+
- Type: `map[string]string`
27+
1928
#### `COMPLEMENT_DEBUG`
2029
If 1, prints out more verbose logging such as HTTP request/response bodies.
2130
- Type: `bool`

b/blueprints.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,8 @@ type Homeserver struct {
5555
ApplicationServices []ApplicationService
5656
// Optionally override the baseImageURI for blueprint creation
5757
BaseImageURI *string
58+
// Optionally override the baseImageArch for blueprint creation
59+
BaseImageArch *string
5860
}
5961

6062
type User struct {

config/config.go

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,12 @@ type Complement struct {
3030
// blueprints. This image must conform to Complement's rules on containers, such as listening on the
3131
// correct ports.
3232
BaseImageURI string
33+
// Name: COMPLEMENT_BASE_ARCH
34+
// Default: ""
35+
// Description: The architecture of the Docker image to use as a base homeserver when generating
36+
// blueprints. This can be used to emulate a particular architecture with a multi-platform image.
37+
// If "", the architecture of the host running Complement is used.
38+
BaseImageArch string
3339
// Name: COMPLEMENT_DEBUG
3440
// Default: 0
3541
// Description: If 1, prints out more verbose logging such as HTTP request/response bodies.
@@ -71,6 +77,11 @@ type Complement struct {
7177
// for the `hs1` homeserver in blueprints, but not any other homeserver (e.g `hs2`). This matching
7278
// is case-insensitive. This allows Complement to test how different homeserver implementations work with each other.
7379
BaseImageURIs map[string]string
80+
// Name: COMPLEMENT_BASE_ARCH_*
81+
// Description: This allows you to set the architecture of the base image used for a particular named homeserver.
82+
// For example, `COMPLEMENT_BASE_ARCH_HS1=arm64` would use an `arm64` image for the `hs1` homeserver in blueprints,
83+
// but not any other homeserver (e.g `hs2`). This matching is case-insensitive.
84+
BaseImageArchs map[string]string
7485

7586
// The namespace for all complement created blueprints and deployments
7687
PackageNamespace string
@@ -118,14 +129,19 @@ type Complement struct {
118129
PostTestScript string
119130
}
120131

121-
var hsRegex = regexp.MustCompile(`COMPLEMENT_BASE_IMAGE_(.+)=(.+)$`)
132+
var hsUriRegex = regexp.MustCompile(`COMPLEMENT_BASE_IMAGE_(.+)=(.+)$`)
133+
var hsArchRegex = regexp.MustCompile(`COMPLEMENT_BASE_ARCH_(.+)=(.+)$`)
122134

123135
func NewConfigFromEnvVars(pkgNamespace, baseImageURI string) *Complement {
124-
cfg := &Complement{BaseImageURIs: map[string]string{}}
136+
cfg := &Complement{
137+
BaseImageURIs: map[string]string{},
138+
BaseImageArchs: map[string]string{},
139+
}
125140
cfg.BaseImageURI = os.Getenv("COMPLEMENT_BASE_IMAGE")
126141
if cfg.BaseImageURI == "" {
127142
cfg.BaseImageURI = baseImageURI
128143
}
144+
cfg.BaseImageArch = os.Getenv("COMPLEMENT_BASE_ARCH")
129145
cfg.DebugLoggingEnabled = os.Getenv("COMPLEMENT_DEBUG") == "1"
130146
cfg.AlwaysPrintServerLogs = os.Getenv("COMPLEMENT_ALWAYS_PRINT_SERVER_LOGS") == "1"
131147
cfg.EnableDirtyRuns = os.Getenv("COMPLEMENT_ENABLE_DIRTY_RUNS") == "1"
@@ -153,10 +169,14 @@ func NewConfigFromEnvVars(pkgNamespace, baseImageURI string) *Complement {
153169
for _, env := range os.Environ() {
154170
// FindStringSubmatch returns the complete match as well as the capture groups.
155171
// In this case we expect there to be 3 matches.
156-
if matches := hsRegex.FindStringSubmatch(env); len(matches) == 3 {
172+
if matches := hsUriRegex.FindStringSubmatch(env); len(matches) == 3 {
157173
hs := matches[1] // first capture group; homeserver name
158174
cfg.BaseImageURIs[hs] = matches[2] // second capture group; homeserver image
159175
}
176+
if matches := hsArchRegex.FindStringSubmatch(env); len(matches) == 3 {
177+
hs := matches[1] // first capture group; homeserver name
178+
cfg.BaseImageArchs[hs] = matches[2] // second capture group; homeserver arch
179+
}
160180
}
161181

162182
cfg.PackageNamespace = pkgNamespace

internal/docker/builder.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -398,18 +398,23 @@ func (d *Builder) constructHomeserver(blueprintName string, runner *instruction.
398398
func (d *Builder) deployBaseImage(blueprintName string, hs b.Homeserver, contextStr, networkName string) (*HomeserverDeployment, error) {
399399
asIDToRegistrationMap := asIDToRegistrationFromLabels(labelsForApplicationServices(hs))
400400
var baseImageURI string
401+
var baseImageArch string
401402
if hs.BaseImageURI == nil {
402403
baseImageURI = d.Config.BaseImageURI
403404
// Use HS specific base image if defined
404405
if uri, ok := d.Config.BaseImageURIs[hs.Name]; ok {
405406
baseImageURI = uri
406407
}
408+
if arch, ok := d.Config.BaseImageArchs[hs.Name]; ok {
409+
baseImageArch = arch
410+
}
407411
} else {
408412
baseImageURI = *hs.BaseImageURI
413+
baseImageArch = *hs.BaseImageArch
409414
}
410415

411416
return deployImage(
412-
d.Docker, baseImageURI, fmt.Sprintf("complement_%s", contextStr),
417+
d.Docker, baseImageURI, baseImageArch, fmt.Sprintf("complement_%s", contextStr),
413418
d.Config.PackageNamespace, blueprintName, hs.Name, asIDToRegistrationMap, contextStr,
414419
networkName, d.Config,
415420
)

internal/docker/deployer.go

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ import (
3939
"github.com/docker/docker/api/types/image"
4040
"github.com/docker/docker/api/types/mount"
4141
"github.com/docker/docker/api/types/network"
42+
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
4243

4344
"github.com/matrix-org/complement/config"
4445
)
@@ -90,10 +91,14 @@ func (d *Deployer) CreateDirtyServer(hsName string) (*HomeserverDeployment, erro
9091
if uri, ok := d.config.BaseImageURIs[hsName]; ok {
9192
baseImageURI = uri
9293
}
94+
baseImageArch := d.config.BaseImageArch
95+
if arch, ok := d.config.BaseImageArchs[hsName]; ok {
96+
baseImageArch = arch
97+
}
9398

9499
containerName := fmt.Sprintf("complement_%s_dirty_%s", d.config.PackageNamespace, hsName)
95100
hsDeployment, err := deployImage(
96-
d.Docker, baseImageURI, containerName,
101+
d.Docker, baseImageURI, baseImageArch, containerName,
97102
d.config.PackageNamespace, "", hsName, nil, "dirty",
98103
networkName, d.config,
99104
)
@@ -172,7 +177,7 @@ func (d *Deployer) Deploy(ctx context.Context, blueprintName string) (*Deploymen
172177
// TODO: Make CSAPI port configurable
173178
containerName := fmt.Sprintf("complement_%s_%s_%s_%d", d.config.PackageNamespace, d.DeployNamespace, contextStr, counter)
174179
deployment, err := deployImage(
175-
d.Docker, img.ID, containerName,
180+
d.Docker, img.ID, "", containerName,
176181
d.config.PackageNamespace, blueprintName, hsName, asIDToRegistrationMap, contextStr, networkName, d.config,
177182
)
178183
if err != nil {
@@ -329,7 +334,7 @@ func (d *Deployer) StartServer(hsDep *HomeserverDeployment) error {
329334

330335
// nolint
331336
func deployImage(
332-
docker *client.Client, imageID string, containerName, pkgNamespace, blueprintName, hsName string,
337+
docker *client.Client, imageID, imageArch, containerName, pkgNamespace, blueprintName, hsName string,
333338
asIDToRegistrationMap map[string]string, contextStr, networkName string, cfg *config.Complement,
334339
) (*HomeserverDeployment, error) {
335340
ctx := context.Background()
@@ -402,7 +407,10 @@ func deployImage(
402407
Aliases: []string{hsName},
403408
},
404409
},
405-
}, nil, containerName)
410+
}, &ocispec.Platform{
411+
OS: "linux",
412+
Architecture: imageArch,
413+
}, containerName)
406414
if err != nil {
407415
return nil, err
408416
}

0 commit comments

Comments
 (0)