Skip to content

Commit 287669e

Browse files
committed
Started work on docker-out feature
1 parent b04fd19 commit 287669e

14 files changed

Lines changed: 425 additions & 15 deletions

File tree

.github/workflows/ci.yml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,11 @@ jobs:
1414
build:
1515
strategy:
1616
matrix:
17-
feature: ["go", "zig"]
17+
feature: [
18+
#"docker-out",
19+
"go",
20+
"zig"
21+
]
1822
runs-on: ubuntu-latest
1923
permissions:
2024
contents: read

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ Below is a list with included features, click on the link for more details.
1515

1616
| Name | Description |
1717
| --- | --- |
18+
| [docker-out](./features/src/docker-out/README.md) | A feature which installs the Docker client and re-uses the host socket. |
1819
| [go](./features/src/go/README.md) | A feature which installs Go. |
1920
| [zig](./features/src/zig/README.md) | A feature which installs Zig. |
2021

build/build.go

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import (
2020
////////////////////////////////////////////////////////////
2121

2222
var featureList = []string{
23+
"docker-out",
2324
"go",
2425
"zig",
2526
}
@@ -46,7 +47,18 @@ func init() {
4647
return nil
4748
})
4849

49-
////////// Go
50+
////////// docker-out
51+
gotaskr.Task("Feature:docker-out:Package", func() error {
52+
return packageFeature("docker-out")
53+
})
54+
gotaskr.Task("Feature:docker-out:Test", func() error {
55+
return testFeature("docker-out")
56+
})
57+
gotaskr.Task("Feature:docker-out:Publish", func() error {
58+
return publishFeature("docker-out")
59+
})
60+
61+
////////// go
5062
gotaskr.Task("Feature:go:Package", func() error {
5163
return packageFeature("go")
5264
})
@@ -57,7 +69,7 @@ func init() {
5769
return publishFeature("go")
5870
})
5971

60-
////////// Zig
72+
////////// zig
6173
gotaskr.Task("Feature:zig:Package", func() error {
6274
return packageFeature("zig")
6375
})

features/src/docker-out/README.md

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# Docker outside Docker (docker-out)
2+
3+
A feature which installs the Docker client and re-uses the host socket.
4+
5+
## Example Usage
6+
7+
```json
8+
"features": {
9+
"ghcr.io/postfinance/devcontainer-features/docker-out:1.0.0": {
10+
"version": "latest",
11+
"composeVersion": "latest",
12+
"buildxVersion": "latest"
13+
}
14+
}
15+
```
16+
17+
## Options
18+
19+
| Option | Description | Type | Default Value | Proposals |
20+
|-----|-----|-----|-----|-----|
21+
| version | The version of the Docker CLI to install. | string | latest | latest, 20.10 |
22+
| composeVersion | The version of the Compose plugin to install. | string | latest | latest, 2.39.1, 2.29 |
23+
| buildxVersion | The version of the buildx plugin to install. | string | latest | latest, 0.26.1, 0.10 |
24+
25+
## Customizations
26+
27+
### VS Code Extensions
28+
29+
- `ms-azuretools.vscode-docker`
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
{
2+
"id": "docker-out",
3+
"version": "1.0.0",
4+
"name": "Docker outside Docker",
5+
"description": "A feature which installs the Docker client and re-uses the host socket.",
6+
"options": {
7+
"version": {
8+
"type": "string",
9+
"proposals": [
10+
"latest",
11+
"20.10"
12+
],
13+
"default": "latest",
14+
"description": "The version of the Docker CLI to install."
15+
},
16+
"composeVersion": {
17+
"type": "string",
18+
"proposals": [
19+
"latest",
20+
"2.39.1",
21+
"2.29"
22+
],
23+
"default": "latest",
24+
"description": "The version of the Compose plugin to install."
25+
},
26+
"buildxVersion": {
27+
"type": "string",
28+
"proposals": [
29+
"latest",
30+
"0.26.1",
31+
"0.10"
32+
],
33+
"default": "latest",
34+
"description": "The version of the buildx plugin to install."
35+
}
36+
},
37+
"customizations": {
38+
"vscode": {
39+
"extensions": [
40+
"ms-azuretools.vscode-docker"
41+
]
42+
}
43+
},
44+
"mounts": [
45+
{
46+
"source": "/var/run/docker.sock",
47+
"target": "/var/run/docker.sock",
48+
"type": "bind"
49+
}
50+
],
51+
"entrypoint": "/usr/local/share/docker-init.sh"
52+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
#!/usr/bin/env bash
2+
set -e
3+
4+
# Create a matching docker group in the container and add the current user to it
5+
SOCKET_GID=$(stat -c '%g' /var/run/docker.sock)
6+
sudo groupadd -g $SOCKET_GID docker
7+
sudo usermod -a -G docker $(whoami)
8+
9+
# Execute whatever commands were passed in (if any). This allows us
10+
# to set this script to ENTRYPOINT while still executing the default CMD.
11+
set +e
12+
exec "$@"

features/src/docker-out/install.sh

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
case $(uname -m | tr '[:upper:]' '[:lower:]') in
2+
x86_64*) ARCH=amd64 ;;
3+
arm*|aarch64*) ARCH=arm64 ;;
4+
*) echo "Unsupported architecture: $(uname -m)" >&2; exit 1 ;;
5+
esac
6+
7+
"./installer_$ARCH" \
8+
-version="${VERSION:-"latest"}" \
9+
-composeVersion="${COMPOSEVERSION:-"latest"}" \
10+
-buildxVersion="${BUILDXVERSION:-"latest"}"
Lines changed: 183 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,183 @@
1+
package main
2+
3+
import (
4+
"builder/installer"
5+
"flag"
6+
"fmt"
7+
"os"
8+
"path/filepath"
9+
"regexp"
10+
11+
"github.com/roemer/gotaskr/execr"
12+
"github.com/roemer/gover"
13+
)
14+
15+
//////////
16+
// Configuration
17+
//////////
18+
19+
var downloadRegistryBase = "https://download.docker.com"
20+
var downloadRegistryPath = "/linux/static/stable/x86_64/"
21+
22+
//////////
23+
// Main
24+
//////////
25+
26+
func main() {
27+
if err := runMain(); err != nil {
28+
fmt.Printf("Error: %v\n", err)
29+
os.Exit(1)
30+
}
31+
}
32+
33+
func runMain() error {
34+
// Handle the flags
35+
version := flag.String("version", "latest", "The version of the Docker CLI to install.")
36+
composeVersion := flag.String("composeVersion", "latest", "The version of the Compose plugin to install.")
37+
buildxVersion := flag.String("buildxVersion", "latest", "The version of the buildx plugin to install.")
38+
39+
flag.Parse()
40+
41+
// Create and process the feature
42+
feature := installer.NewFeature("Docker-Out", false,
43+
&dockerCliComponent{
44+
ComponentBase: installer.NewComponentBase("Docker CLI", *version, false),
45+
},
46+
&dockerComposeComponent{
47+
ComponentBase: installer.NewComponentBase("Docker Compose", *composeVersion, false),
48+
},
49+
&dockerBuildxComponent{
50+
ComponentBase: installer.NewComponentBase("Docker buildx", *buildxVersion, false),
51+
},
52+
)
53+
return feature.Process()
54+
}
55+
56+
//////////
57+
// Implementation
58+
//////////
59+
60+
type dockerCliComponent struct {
61+
*installer.ComponentBase
62+
}
63+
64+
func (c *dockerCliComponent) GetAllVersions() ([]*gover.Version, error) {
65+
url, err := installer.Tools.Http.BuildUrl(downloadRegistryBase, downloadRegistryPath)
66+
if err != nil {
67+
return nil, err
68+
}
69+
versionRegexp := regexp.MustCompile(`(?m)^(\d+)\.(\d+)\.(\d+)$`)
70+
allVersions, err := installer.Tools.Http.GetVersionsFromHtmlIndex(
71+
url,
72+
regexp.MustCompile(`^.*<a href="docker-([0-9\.]+).tgz">.*$`),
73+
versionRegexp)
74+
if err != nil {
75+
return nil, err
76+
}
77+
return allVersions, nil
78+
}
79+
80+
func (c *dockerCliComponent) InstallVersion(version *gover.Version) error {
81+
// Download the file
82+
fileName := fmt.Sprintf("docker-%s.tgz", version.Raw)
83+
downloadUrl, err := installer.Tools.Http.BuildUrl(downloadRegistryBase, downloadRegistryPath, fileName)
84+
if err != nil {
85+
return err
86+
}
87+
if err := installer.Tools.Download.ToFile(downloadUrl, fileName, "Docker CLI"); err != nil {
88+
return err
89+
}
90+
defer os.Remove(fileName)
91+
// Extract it
92+
tempDir, err := os.MkdirTemp("", "docker-extract")
93+
if err != nil {
94+
return err
95+
}
96+
defer os.RemoveAll(tempDir)
97+
if err := installer.Tools.Compression.ExtractTarGz(fileName, tempDir, false); err != nil {
98+
return err
99+
}
100+
// Move the desired files
101+
if err := installer.Tools.FileSystem.MoveFile(filepath.Join(tempDir, "docker/docker"), "/usr/local/bin/docker"); err != nil {
102+
return err
103+
}
104+
105+
// Copy the startup file
106+
if err := execr.Run(true, "cp", "-prf", "docker-init.sh", "/usr/local/share/docker-init.sh"); err != nil {
107+
return err
108+
}
109+
110+
return nil
111+
}
112+
113+
type dockerComposeComponent struct {
114+
*installer.ComponentBase
115+
}
116+
117+
func (c *dockerComposeComponent) GetAllVersions() ([]*gover.Version, error) {
118+
versionRegexp := regexp.MustCompile(`(?m)^v(\d+)\.(\d+)\.(\d+)$`)
119+
versions := []*gover.Version{}
120+
allTags, err := installer.Tools.GitHub.GetTags("docker", "compose")
121+
if err != nil {
122+
return nil, err
123+
}
124+
for _, tag := range allTags {
125+
if versionRegexp.MatchString(tag.Name) {
126+
version, err := gover.ParseVersionFromRegex(tag.Name, versionRegexp)
127+
if err != nil {
128+
return nil, err
129+
}
130+
versions = append(versions, version)
131+
}
132+
}
133+
return versions, nil
134+
}
135+
136+
func (c *dockerComposeComponent) InstallVersion(version *gover.Version) error {
137+
// Download the file
138+
downloadUrl := fmt.Sprintf("https://github.com/docker/compose/releases/download/%s/docker-compose-linux-x86_64", version.Raw)
139+
if err := installer.Tools.Download.ToFile(downloadUrl, "/usr/local/lib/docker/cli-plugins/docker-compose", "Docker Compose"); err != nil {
140+
return err
141+
}
142+
// Apply executable permissions
143+
if err := execr.Run(true, "chmod", "+x", "/usr/local/lib/docker/cli-plugins/docker-compose"); err != nil {
144+
return err
145+
}
146+
return nil
147+
}
148+
149+
type dockerBuildxComponent struct {
150+
*installer.ComponentBase
151+
}
152+
153+
func (c *dockerBuildxComponent) GetAllVersions() ([]*gover.Version, error) {
154+
versionRegexp := regexp.MustCompile(`(?m)^v(\d+)\.(\d+)\.(\d+)$`)
155+
versions := []*gover.Version{}
156+
allTags, err := installer.Tools.GitHub.GetTags("docker", "buildx")
157+
if err != nil {
158+
return nil, err
159+
}
160+
for _, tag := range allTags {
161+
if versionRegexp.MatchString(tag.Name) {
162+
version, err := gover.ParseVersionFromRegex(tag.Name, versionRegexp)
163+
if err != nil {
164+
return nil, err
165+
}
166+
versions = append(versions, version)
167+
}
168+
}
169+
return versions, nil
170+
}
171+
172+
func (c *dockerBuildxComponent) InstallVersion(version *gover.Version) error {
173+
// Download the file
174+
downloadUrl := fmt.Sprintf("https://github.com/docker/buildx/releases/download/%s/buildx-%s.linux-amd64", version.Raw, version.Raw)
175+
if err := installer.Tools.Download.ToFile(downloadUrl, "/usr/local/lib/docker/cli-plugins/docker-buildx", "Docker buildx"); err != nil {
176+
return err
177+
}
178+
// Apply executable permissions
179+
if err := execr.Run(true, "chmod", "+x", "/usr/local/lib/docker/cli-plugins/docker-buildx"); err != nil {
180+
return err
181+
}
182+
return nil
183+
}

features/src/go/installer.go

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import (
55
"encoding/json"
66
"flag"
77
"fmt"
8-
"net/url"
98
"os"
109
"regexp"
1110
"runtime"
@@ -60,10 +59,6 @@ func runMain() error {
6059
return feature.Process()
6160
}
6261

63-
func buildUrl(base string, parts ...string) (string, error) {
64-
return url.JoinPath(base, parts...)
65-
}
66-
6762
//////////
6863
// Implementation
6964
//////////
@@ -125,7 +120,7 @@ func (c *goComponent) InstallVersion(version *gover.Version) error {
125120
return fmt.Errorf("unsupported architecture: %s", runtime.GOARCH)
126121
}
127122

128-
downloadUrl, err := buildUrl(c.DownloadRegistryBase, c.DownloadRegistryPath, fileName)
123+
downloadUrl, err := installer.Tools.Http.BuildUrl(c.DownloadRegistryBase, c.DownloadRegistryPath, fileName)
129124
if err != nil {
130125
return err
131126
}

0 commit comments

Comments
 (0)