Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 7504b5e

Browse files
committedMar 22, 2024
feat: docker image
1 parent 8342aa3 commit 7504b5e

File tree

13 files changed

+202
-475
lines changed

13 files changed

+202
-475
lines changed
 

‎.gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,5 @@ privkey.pub
55
public
66
build
77
assets/jmattheis-resume.pdf
8+
docker/registry/busybox/
9+
gemini_cache/

‎README.md

+1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ curl tftp://jmattheis.de
1717
dict -h jmattheis.de -I
1818
dig @jmattheis.de +tcp +short
1919
docker -H jmattheis.de inspect -f '{{.Value}}' start
20+
docker run --rm jmattheis.de/start
2021
finger jmattheis.de
2122
gemget gemini://jmattheis.de/ -o-
2223
netcat jmattheis.de 23

‎assets/index.html

+1
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@ <h2>Hacky</h2>
114114
$ dict -h jmattheis.de -I
115115
$ dig @jmattheis.de +tcp +short
116116
$ docker -H jmattheis.de inspect -f '{{`{{.Value}}`}}' start
117+
$ docker run --rm jmattheis.de/start
117118
$ finger jmattheis.de
118119
$ gemget gemini://jmattheis.de/ -o-
119120
$ netcat jmattheis.de 23

‎content/text.go

+1
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ Try one of the following commands in your terminal:
3636
dict -h jmattheis.de -I
3737
dig @jmattheis.de +tcp +short
3838
docker -H jmattheis.de inspect -f '{{.Value}}' start
39+
docker run --rm jmattheis.de/start
3940
finger jmattheis.de
4041
gemget gemini://jmattheis.de/ -o-
4142
netcat jmattheis.de 23

‎docker/registry/builder.go

+76
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
package dockerregistry
2+
3+
import (
4+
"encoding/json"
5+
6+
"github.com/distribution/distribution/v3"
7+
"github.com/distribution/distribution/v3/manifest/ocischema"
8+
"github.com/opencontainers/go-digest"
9+
v1 "github.com/opencontainers/image-spec/specs-go/v1"
10+
)
11+
12+
type Entry struct {
13+
Digest digest.Digest
14+
MediaType string
15+
Content []byte
16+
}
17+
18+
func DockerStdout(content string) map[string]Entry {
19+
var bManifests ocischema.DeserializedImageIndex
20+
check(bManifests.UnmarshalJSON(read("manifest.json")))
21+
22+
store := map[string]Entry{}
23+
24+
var newManifestDescriptions []distribution.Descriptor
25+
for _, maniDesc := range bManifests.Manifests {
26+
m := ocischema.Manifest{}
27+
check(json.Unmarshal(read(maniDesc.Digest.Encoded()+".manifest.json"), &m))
28+
m.Annotations = nil
29+
30+
cfg := v1.Image{}
31+
check(json.Unmarshal(read(m.Config.Digest.Encoded()), &cfg))
32+
cfg.Config.Cmd = []string{"echo", content}
33+
m.Config.Digest, m.Config.Size = registerJson(store, "application/octet-stream", cfg)
34+
35+
for _, layer := range m.Layers {
36+
registerRaw(store, "application/octet-stream", read(layer.Digest.Encoded()))
37+
}
38+
39+
maniDesc.Digest, maniDesc.Size = registerJson(store, v1.MediaTypeImageManifest, m)
40+
41+
newManifestDescriptions = append(newManifestDescriptions, maniDesc)
42+
}
43+
index, err := ocischema.FromDescriptors(newManifestDescriptions, nil)
44+
check(err)
45+
46+
digest, _ := registerJson(store, v1.MediaTypeImageIndex, index)
47+
48+
store["latest"] = Entry{
49+
Digest: digest,
50+
MediaType: v1.MediaTypeImageIndex,
51+
Content: store[digest.String()].Content,
52+
}
53+
return store
54+
}
55+
56+
func registerJson(store map[string]Entry, mediaType string, value any) (digest.Digest, int64) {
57+
b, err := json.Marshal(value)
58+
check(err)
59+
return registerRaw(store, mediaType, b)
60+
}
61+
62+
func registerRaw(store map[string]Entry, mediaType string, b []byte) (digest.Digest, int64) {
63+
d := digest.FromBytes(b)
64+
store[d.String()] = Entry{
65+
Digest: d,
66+
MediaType: mediaType,
67+
Content: b,
68+
}
69+
return d, int64(len(b))
70+
}
71+
72+
func check(err error) {
73+
if err != nil {
74+
panic(err)
75+
}
76+
}

‎docker/registry/embed.go

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package dockerregistry
2+
3+
import (
4+
"embed"
5+
"path"
6+
)
7+
8+
//go:embed busybox/*
9+
var images embed.FS
10+
11+
func read(s string) []byte {
12+
b, err := images.ReadFile(path.Join("busybox", s))
13+
check(err)
14+
return b
15+
}

‎docker/registry/generate.go

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
//go:generate rm -rf ./busybox
2+
//go:generate skopeo copy --multi-arch=all docker://index.docker.io/library/busybox:latest dir:./busybox
3+
4+
package dockerregistry

‎docker/registry/http.go

+72
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
package dockerregistry
2+
3+
import (
4+
"fmt"
5+
"io"
6+
"net/http"
7+
"regexp"
8+
"strings"
9+
10+
lru "github.com/hashicorp/golang-lru/v2"
11+
"github.com/jmattheis/website/content"
12+
)
13+
14+
var pattern = regexp.MustCompile(`\/v2\/(.+)\/(blobs|manifests)\/([a-z0-9:]+)`)
15+
16+
func Handler() http.HandlerFunc {
17+
tty := content.SingleText{
18+
Split: "/",
19+
CommandPrefix: "docker run --rm jmattheis.de/",
20+
}
21+
22+
successCache, err := lru.New[string, map[string]Entry](50)
23+
check(err)
24+
errorCache, err := lru.New[string, map[string]Entry](20)
25+
check(err)
26+
27+
return func(w http.ResponseWriter, r *http.Request) {
28+
matches := pattern.FindStringSubmatch(r.URL.Path)
29+
30+
if matches == nil {
31+
io.WriteString(w, "unknown url")
32+
w.WriteHeader(404)
33+
return
34+
}
35+
36+
cmd, t, hash := matches[1], matches[2], matches[3]
37+
38+
content := tty.Get(cmd)
39+
40+
cache := successCache
41+
if strings.HasPrefix(content, "error") {
42+
cache = errorCache
43+
}
44+
45+
store, ok := cache.Get(cmd)
46+
if !ok {
47+
store = DockerStdout(content)
48+
cache.Add(cmd, store)
49+
}
50+
51+
entry, ok := store[hash]
52+
if !ok {
53+
if strings.HasPrefix(hash, "sha256:") {
54+
w.WriteHeader(404)
55+
io.WriteString(w, "unknown hash")
56+
return
57+
}
58+
entry, _ = store["latest"]
59+
}
60+
61+
w.Header().Add("content-type", entry.MediaType)
62+
w.Header().Add("content-length", fmt.Sprint(len(entry.Content)))
63+
w.Header().Add("etag", `"`+entry.Digest.String()+`"`)
64+
if t == "manifests" {
65+
w.Header().Add("Docker-Content-Digest", entry.Digest.String())
66+
}
67+
w.WriteHeader(200)
68+
if r.Method != "HEAD" {
69+
w.Write(entry.Content)
70+
}
71+
}
72+
}

‎docker/docker.go ‎docker/socket/socket.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package docker
1+
package socket
22

33
import (
44
"encoding/json"

‎go.mod

+6-10
Original file line numberDiff line numberDiff line change
@@ -7,40 +7,36 @@ require (
77
git.sr.ht/~adnano/go-gemini v0.2.4
88
github.com/DevelHell/popgun v0.0.0-20170926125504-2c5552e4bf74
99
github.com/NYTimes/gziphandler v1.1.1
10+
github.com/distribution/distribution/v3 v3.0.0-alpha.1
1011
github.com/emersion/go-imap v1.2.1
1112
github.com/emersion/go-message v0.18.0
1213
github.com/fclairamb/ftpserver v0.0.0-20200221221851-84e5d668e655
1314
github.com/gernest/front v0.0.0-20210301115436-8a0b0a782d0a
1415
github.com/gliderlabs/ssh v0.3.6
15-
github.com/gobuffalo/packr/v2 v2.8.3
1616
github.com/gomarkdown/markdown v0.0.0-20231222211730-1d6d20845b47
1717
github.com/gorilla/feeds v1.1.2
1818
github.com/gorilla/websocket v1.5.1
1919
github.com/grokify/html-strip-tags-go v0.1.0
20+
github.com/hashicorp/golang-lru/v2 v2.0.7
2021
github.com/miekg/dns v1.1.58
22+
github.com/opencontainers/go-digest v1.0.0
23+
github.com/opencontainers/image-spec v1.0.2
24+
github.com/pin/tftp/v3 v3.1.0
2125
github.com/rs/zerolog v1.32.0
2226
golang.org/x/crypto v0.21.0
2327
)
2428

2529
require (
2630
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be // indirect
31+
github.com/distribution/reference v0.5.0 // indirect
2732
github.com/emersion/go-sasl v0.0.0-20200509203442-7bfe0ed36a21 // indirect
2833
github.com/emersion/go-textwrapper v0.0.0-20200911093747-65d896831594 // indirect
2934
github.com/go-kit/kit v0.10.0 // indirect
3035
github.com/go-logfmt/logfmt v0.5.0 // indirect
31-
github.com/gobuffalo/logger v1.0.6 // indirect
32-
github.com/gobuffalo/packd v1.0.1 // indirect
33-
github.com/karrick/godirwalk v1.16.1 // indirect
34-
github.com/markbates/errx v1.1.0 // indirect
35-
github.com/markbates/oncer v1.0.0 // indirect
36-
github.com/markbates/safe v1.0.1 // indirect
3736
github.com/mattn/go-colorable v0.1.13 // indirect
3837
github.com/mattn/go-isatty v0.0.19 // indirect
3938
github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5 // indirect
40-
github.com/pin/tftp/v3 v3.1.0 // indirect
4139
github.com/sasha-s/go-deadlock v0.3.1 // indirect
42-
github.com/sirupsen/logrus v1.8.1 // indirect
43-
github.com/stretchr/testify v1.8.1 // indirect
4440
golang.org/x/mod v0.14.0 // indirect
4541
golang.org/x/net v0.21.0 // indirect
4642
golang.org/x/sys v0.18.0 // indirect

0 commit comments

Comments
 (0)
Please sign in to comment.