Skip to content

Commit b2f3119

Browse files
committed
Rewrite in go
Handle #1
1 parent c7a8306 commit b2f3119

File tree

331 files changed

+223465
-585
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

331 files changed

+223465
-585
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,5 @@ build/
66
*.pyc
77
.idea/
88
*.iml
9+
.vscode/
910
image2ipfs/git-revision

image2ipfs-server/Dockerfile renamed to Dockerfile

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,10 @@ FROM golang:1.10 as builder
22

33
WORKDIR /go/src/github.com/jvassev/image2ipfs
44
COPY . .
5-
RUN make install-server
5+
ARG GIT_VERSION
6+
RUN make nested-build GIT_VERSION=$GIT_VERSION
67

78
# Speed up local builds where vendor is populated
89
FROM busybox
9-
ENTRYPOINT ["image2ipfs-server"]
10-
COPY --from=builder /go/bin/image2ipfs-server /bin
10+
ENTRYPOINT ["image2ipfs", "server"]
11+
COPY --from=builder /go/bin/image2ipfs /bin

Gopkg.lock

Lines changed: 20 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Makefile

Lines changed: 35 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,55 +1,57 @@
11
TAG ?= latest
22
IMAGE ?= jvassev/ipfs-registry
33
DOCKER_BUILD_ARGS ?=
4+
PKG := github.com/jvassev/image2ipfs
5+
IPFS_GATEWAY ?= http://localhost:8080
46

5-
IPFS_GATEWAY ?= http://localhost:8080
6-
7-
dist: version
8-
python setup.py sdist
9-
10-
lint:
11-
cd image2ipfs && pylint --rcfile pylint.rc *.py
7+
VERSION := 0.1.0
8+
GIT_VERSION ?= $(shell git rev-parse HEAD)
9+
LDFLAGS := -X github.com/jvassev/image2ipfs/util.Version=$(VERSION)/$(GIT_VERSION) -w -s
1210

1311
test:
14-
cd image2ipfs && python -m unittest discover
15-
16-
17-
clean:
18-
rm -fr image2ipfs/*.pyc
19-
rm -fr dist/ build/ *.egg-info
20-
21-
install: clean version
22-
python setup.py install
23-
image2ipfs --version
12+
go test -v $(PKG)
2413

25-
version:
26-
@git describe --match 'v[0-9]*' --dirty='.m' --always > image2ipfs/git-revision
27-
@cat image2ipfs/git-revision
14+
install: test
15+
CGO_ENABLED=0 go install -v -ldflags "$(LDFLAGS)" $(PKG)
2816

29-
upload: clean
30-
python setup.py sdist upload
17+
build-image: test
18+
CGO_ENABLED=0 docker build $(DOCKER_BUILD_ARGS) -t $(IMAGE):$(TAG) --build-arg GIT_VERSION=$(GIT_VERSION) .
3119

32-
33-
build-image:
34-
docker build $(DOCKER_BUILD_ARGS) -t $(IMAGE):$(TAG) -f image2ipfs-server/Dockerfile .
35-
docker tag $(IMAGE):$(TAG) $(IMAGE):latest
20+
nested-build: test
21+
CGO_ENABLED=0 GOARCH=amd64 GOOS=linux go install -v -ldflags "$(LDFLAGS)" $(PKG)
3622

3723
shell:
38-
docker run --rm -ti -u root -v `pwd`:/workspace --entrypoint=/bin/sh $(IMAGE)
24+
docker run --rm -ti -u root -v `pwd`:/workspace --entrypoint=/bin/sh $(IMAGE):$(TAG)
3925

4026
push-image: build-image
4127
docker push $(IMAGE):$(TAG)
4228

43-
attach:
44-
@docker exec -ti $(CONT) /bin/bash
45-
4629
guess-tag:
4730
@echo TAG=`git describe --match 'v[0-9]*' --dirty='.m' --always`
4831

49-
install-server:
50-
CGO_ENABLED=0 go install github.com/jvassev/image2ipfs/image2ipfs-server
51-
5232
run-server: build-image
5333
docker run -ti --rm \
5434
--net=host \
5535
$(IMAGE):$(TAG)
36+
37+
clean:
38+
rm -fr dist
39+
40+
dist: clean test dist-linux dist-mac dist-win
41+
42+
dist-linux:
43+
@mkdir -p dist
44+
GOARCH=amd64 GOOS=linux CGO_ENABLED=0 go build -o dist/image2ipfs -v -ldflags "$(LDFLAGS)" $(PKG)
45+
gzip -S -$(VERSION)_amd64_linux.gz dist/image2ipfs
46+
47+
dist-mac:
48+
@mkdir -p dist
49+
GOARCH=amd64 GOOS=darwin CGO_ENABLED=0 go build -o dist/image2ipfs -v -ldflags "$(LDFLAGS)" $(PKG)
50+
gzip -S -$(VERSION)_amd64_darwin.gz dist/image2ipfs
51+
52+
dist-win:
53+
@mkdir -p dist
54+
GOARCH=amd64 GOOS=windows CGO_ENABLED=0 go build -o dist/image2ipfs.exe -v -ldflags "$(LDFLAGS)" $(PKG)
55+
gzip -cvf dist/image2ipfs.exe > dist/image2ipfs-$(VERSION)_amd64_windows.gz
56+
rm dist/image2ipfs.exe
57+

README.md

Lines changed: 79 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ image2ipfs works only with images prduced docker >= 1.10. On the bright side, al
99
image2ipfs takes an image archive produced using `docker save`.
1010
The archive is extracted to a temp location then processed a bit. Finally, it is added to IPFS using `ipfs add -r`
1111
(you need to have the ipfs binary in your `PATH`). For a simple busybox image
12-
image2ipfs will produce a work dir like this:
12+
image2ipfs will produce something like this:
1313
```
1414
busybox
1515
├── blobs
@@ -23,11 +23,10 @@ busybox
2323
_v1 Manifests are not supported starting with version 0.0.6_
2424
But how do you get from something like QmQSF1oN4TXeU2kRvmjerEs62ZYfKPyRCqPvW1XTTc4fLS to a working `docker pull busybox`?
2525

26-
The answer is simple: using url rewriting. In the `registry/` subdirectory of the project
27-
there is a trivial Go application that speaks the Registry v2 protocol but instead of serving the blobs and manifests it redirects
26+
The answer is simple: using url rewriting.There is a trivial Go application that speaks the Registry v2 protocol but instead of serving the blobs and manifests it redirects
2827
to an IPFS gateway of your choice.
2928

30-
When pulling REPO:latest (with REPO=busybox in this example), Docker daemon will issue these requests:
29+
When pulling REPO:latest (with REPO=busybox in this example), Docker daemon will issue (roughly) these requests:
3130
```
3231
GET /v2/
3332
GET /v2/REPO/manifest/latest
@@ -36,7 +35,7 @@ GET /v2/REPO/blobs/sha256:193bda8d9ac77416619eb556391a9c5447adb2abf12aab515d1b0c
3635
GET /v2/REPO/blobs/sha256:a1b1b81d3d1afdb8fe119b002318c12c20934713b9754a40f702adb18a2540b9
3736
```
3837

39-
All the Go app does is produce IPFS links to a an IPFS gateway and redirect docker there:
38+
The Go app serves redirects to an IPFS gateway like so:
4039
```
4140
GET /ipfs/HASH/manifest/latest
4241
GET /ipfs/HASH/blobs/sha256:47bcc53f74dc94b1920f0b34f6036096526296767650f223433fe65c35f149eb
@@ -48,21 +47,12 @@ GET /ipfs/HASH/blobs/sha256:a1b1b81d3d1afdb8fe119b002318c12c20934713b9754a40f702
4847
# Installation
4948
```bash
5049
$ git clone https://github.com/jvassev/image2ipfs
51-
$ cd image2ipfs
5250

5351
# this will install a python command so pyenv or virtualenv is recommended rather than sudo
5452
$ make install
5553

56-
$ image2ipfs -v
57-
0.0.6
58-
```
59-
60-
You can also install using pip
61-
```bash
62-
$ pip install image2ipfs
63-
64-
$ image2ipfs -v
65-
0.0.6
54+
$ image2ipfs --version
55+
0.1.0
6656
```
6757

6858
# Running the registry
@@ -72,18 +62,58 @@ You can pull the official image from dockerhub. This example assumes the gateway
7262
docker run -td --name ipfs-registry -e IPFS_GATEWAY=http://localhost:8080 --net host jvassev/ipfs-registry
7363
```
7464

75-
Or build from source:
65+
Or build from source and skip Docker:
7666
```bash
77-
# build image locally
78-
make build-image
67+
$ make install
68+
69+
$ image2ipfs server
70+
2019/03/12 15:43:58 Using IPFS gateway http://127.0.0.1:8080
71+
2019/03/12 15:43:58 Serving on :5000
72+
```
73+
74+
# Synopsis
75+
76+
The client and server live in the same binary. You can find prebuilt releases for Linux, Mac and Windows on the Releases page. The command flags are compatible with the legacy Python version.
77+
78+
```
79+
usage: image2ipfs [<flags>] <command> [<args> ...]
7980
80-
# or install to $GOPATH/bin
81-
make install
81+
Flags:
82+
--help Show context-sensitive help (also try --help-long and --help-man).
83+
--version Show application version.
84+
-r, --registry="http://localhost:5000"
85+
Registry to use when generating pull URL
86+
-n, --no-add Don`t add to IPFS, just print directory
87+
-q, --quiet Produce less output - just the final pullable image name
88+
-d, --debug Leave workdir intact (useful for debugging)
89+
-i, --input="-" Docker image archive to process, defaults to stdin. Use - to explicitly set stdin
90+
91+
Commands:
92+
help [<command>...]
93+
Show help.
94+
95+
96+
client [<flags>]
97+
Populate IPFS node with image data
98+
99+
-r, --registry="http://localhost:5000"
100+
Registry to use when generating pull URL
101+
-n, --no-add Don`t add to IPFS, just print directory
102+
-q, --quiet Produce less output - just the final pullable image name
103+
-d, --debug Leave workdir intact (useful for debugging)
104+
-i, --input="-" Docker image archive to process, defaults to stdin. Use - to explicitly set stdin
105+
106+
server [<flags>]
107+
Run an IFPS-backed registry
108+
109+
--gateway="http://127.0.0.1:8080"
110+
IPFS gateway. It must be reachable by pulling clients
111+
--addr=":5000" Listen address.
82112
```
83113

84114
# Configure Docker
85115

86-
As usual add `--insecure-registry localhost:5000` to your docker daemon args
116+
As usual add `--insecure-registry localhost:5000` to your docker daemon args. You need to put the `image2ipfs server` behind a reverse proxy if you want to do proper TLS termination.
87117

88118
# Demo
89119
Assuming you have completed the steps above, let's publish a centos:7 image to IPFS!
@@ -105,74 +135,63 @@ Server:
105135
Built: Sun May 1 20:27:17 2016
106136
OS/Arch: linux/amd64
107137

108-
$ image2ipfs -v
109-
0.0.6
138+
$ image2ipfs --version
139+
0.1.0
110140

111141
$ docker pull centos:7
112142
7: Pulling from library/centos
113-
fa5be2806d4c: Pull complete
114-
2ebc6e0c744d: Pull complete
115-
044c0f15c4d9: Pull complete
116-
28e524afdd05: Pull complete
117-
Digest: sha256:b3da5267165bbaa9a75d8ee21a11728c6fba98c0944dfa28f15c092877bb4391
143+
a02a4930cb5d: Pull complete
144+
Digest: sha256:184e5f35598e333bfa7de10d8fb1cebb5ee4df5bc0f970bf2b1e7c7345136426
118145
Status: Downloaded newer image for centos:7
119146

120147
$ docker save centos:7 | image2ipfs
121-
Extracting to /tmp/tmpluDoZF
122-
Preparing image in /tmp/tmp3iBMaF
123-
Processing centos@sha256:49dccac9d468cc1d3d9a3eafb835d79ed56b99c931ab232774d32b75d220d241
124-
Compressing layer /tmp/tmpluDoZF/768d4f50f65f00831244703e57f64134771289e3de919a576441c9140e037ea2/layer.tar
125-
Compressing layer /tmp/tmpluDoZF/da060eb693ac47689ca545355a060197bd2aadad76ca67535e95838de0737302/layer.tar
126-
Compressing layer /tmp/tmpluDoZF/a3f571afcd5241f02ca23fd50e45a403437d20ae3e215413d602e2deae3f86bc/layer.tar
127-
Compressing layer /tmp/tmpluDoZF/49dccac9d468cc1d3d9a3eafb835d79ed56b99c931ab232774d32b75d220d241/layer.tar
128-
Compressing layer /tmp/tmpluDoZF/49dccac9d468cc1d3d9a3eafb835d79ed56b99c931ab232774d32b75d220d241/layer.tar
129-
Compressing layer /tmp/tmpluDoZF/a3f571afcd5241f02ca23fd50e45a403437d20ae3e215413d602e2deae3f86bc/layer.tar
130-
Compressing layer /tmp/tmpluDoZF/da060eb693ac47689ca545355a060197bd2aadad76ca67535e95838de0737302/layer.tar
131-
Compressing layer /tmp/tmpluDoZF/768d4f50f65f00831244703e57f64134771289e3de919a576441c9140e037ea2/layer.tar
132-
Image ready: QmdLmBErojQctCn9MHMV61BNA6ue2fyDZZAvFRF32cccTT
133-
Browse image at http://localhost:8080/ipfs/QmdLmBErojQctCn9MHMV61BNA6ue2fyDZZAvFRF32cccTT
134-
Dockerized hash ciqn5zu57ciucp3gw2hwxymuwz3tgjlvfdfwg3xhwx456y4xxydkhmq
135-
You can pull using localhost:5000/ciqn5zu57ciucp3gw2hwxymuwz3tgjlvfdfwg3xhwx456y4xxydkhmq/centos
136-
localhost:5000/ciqn5zu57ciucp3gw2hwxymuwz3tgjlvfdfwg3xhwx456y4xxydkhmq/centos
148+
docker save centos:7 | /home/jvassev/more/gohome/bin/image2ipfs
149+
2019/03/12 15:38:59 workdir is /tmp/image2ipfs887013748
150+
2019/03/12 15:39:01 processing centos:7
151+
2019/03/12 15:39:01 processing layer /tmp/image2ipfs887013748/9841c41d4b0d8fe3bf22b7c3c12e7633870218fffec04d84e7d62993ac175a19/layer.tar
152+
2019/03/12 15:39:11 using ipfs in /home/jvassev/.bin/ipfs
153+
2019/03/12 15:39:12 image ready Qmcsr3naQWG6YzeWTCa7Ee55JUqDdAwvo3j8VyAuRcrHvM
154+
2019/03/12 15:39:12 browse image at http://localhost:8080/ipfs/Qmcsr3naQWG6YzeWTCa7Ee55JUqDdAwvo3j8VyAuRcrHvM
155+
2019/03/12 15:39:12 dockerized hash ciqnqalrqxnqzubb2jllburc4e6wt2j7crjx2nxsdfbiw4sceq367lq
156+
2019/03/12 15:39:12 you can pull using localhost:5000/ciqnqalrqxnqzubb2jllburc4e6wt2j7crjx2nxsdfbiw4sceq367lq/centos
157+
localhost:5000/ciqnqalrqxnqzubb2jllburc4e6wt2j7crjx2nxsdfbiw4sceq367lq/centos
137158

138159
# delete the image to make docker pull layers again
139160
$ docker rmi centos:7
140161
```
141162

142-
The last line contains the image name (you can get only it by passing `-q` to image2ipfs). If you have the IPFS registry
143-
running you should be able to pull:
163+
`image2ipfs` will produce a single line to stdout - the pullable docker image name. The rest is debug output you can suppress with `-q`.
144164

145165
```bash
146-
$ docker pull localhost:5000/ciqn5zu57ciucp3gw2hwxymuwz3tgjlvfdfwg3xhwx456y4xxydkhmq/centos
166+
$ docker pull localhost:5000/ciqnqalrqxnqzubb2jllburc4e6wt2j7crjx2nxsdfbiw4sceq367lq/centos
147167
Using default tag: latest
148-
latest: Pulling from ciqn5zu57ciucp3gw2hwxymuwz3tgjlvfdfwg3xhwx456y4xxydkhmq/centos
149-
Digest: sha256:2c863897110a2aa59287df9e4544fb4d15f83b41e44ed578872e6314b1025a1e
150-
Status: Image is up to date for localhost:5000/ciqn5zu57ciucp3gw2hwxymuwz3tgjlvfdfwg3xhwx456y4xxydkhmq/centos:latest
168+
latest: Pulling from ciqnqalrqxnqzubb2jllburc4e6wt2j7crjx2nxsdfbiw4sceq367lq/centos
169+
Digest: sha256:4c7a24018edbcb72ec0e6a7ff6809db4aa2f306784bd79ab971e0497954ed4e2
170+
Status: Downloaded newer image for localhost:5000/ciqnqalrqxnqzubb2jllburc4e6wt2j7crjx2nxsdfbiw4sceq367lq/centos:latest
151171

152-
$ docker history localhost:5000/ciqn5zu57ciucp3gw2hwxymuwz3tgjlvfdfwg3xhwx456y4xxydkhmq/centos
172+
$ docker history localhost:5000/ciqnqalrqxnqzubb2jllburc4e6wt2j7crjx2nxsdfbiw4sceq367lq/centos
153173
IMAGE CREATED CREATED BY SIZE COMMENT
154174
778a53015523 4 weeks ago /bin/sh -c #(nop) CMD ["/bin/bash"] 0 B
155175
<missing> 4 weeks ago /bin/sh -c #(nop) LABEL name=CentOS Base Imag 0 B
156176
<missing> 4 weeks ago /bin/sh -c #(nop) ADD file:6dd89087d4d418ca0c 196.7 MB
157177
<missing> 7 months ago /bin/sh -c #(nop) MAINTAINER The CentOS Proje 0 B
158178
```
159179

160-
Depending on how you have started the ipfs-registry the docker daemon will be redirected to an IPFS gateway of your choice. By default the registry
180+
Depending on how you have started the image2ipfs the docker daemon will be redirected to an IPFS gateway of your choice. By default the registry
161181
will redirect to the ipfs daemon running locally (http://localhost:8080).
162182

163-
But what is this "Dockerized hash ciqn5zu57ciucp3gw2hwxymuwz3tgjlvfdfwg3xhwx456y4xxydkhmq" in the output?
183+
But what is this "dockerized hash ciqnqalrqxnqzubb2jllburc4e6wt2j7crjx2nxsdfbiw4sceq367lq" in the output?
164184
Docker requires image names to be all lowercase which doesn't play nicely with base58-encoded binary. A dockerized IPFS hash
165-
is just a base-32 of the same binary value. This is the reason why the ipfs-registry is not a simple nginx+rewrite rules: you need
166-
to do base-32 to base-58 conversions. If you see a string starting with `ciq` that's probably a dockerized ipfs hash.
167-
(OK, you can also do this with nginx_lua)
185+
is just a base-32 of the same binary value. If you see a string starting with `ciq..` that's probably a dockerized IPFS hash.
168186

169187
In automated scenarios you'd probably want to run image2ipfs like this:
170188
```bash
171189

172190
# build whatever images
173191
$ docker built -t $TAG ...
174-
$ docker save $TAG | image2ipfs -q -r my-gateway.local:9090 | tee pull-url.txt
175-
my-gateway.local:9090/ciq..../centos
192+
193+
# save the resulting image name
194+
$ docker save $TAG | image2ipfs -q -r my-gateway.local:8080 > pull-url.txt
176195
```
177196

178197
`-r my-gateway.local` instructs image2ipfs what pull url to produce. In a CI/CD you can distribute this generated url to downstream jobs that need to pull it.
@@ -183,23 +202,6 @@ Not sure. It would be great if an IPFS gateway could speak the Registry v2 proto
183202

184203
The Dockerized hash can be shortened a bit if base-36 is used instead of base-32/hex.
185204

186-
# Synopsis
187-
188-
```
189-
usage: image2ipfs [-h] [--quiet] [--version] [--input INPUT] [--no-add]
190-
[--registry REGISTRY]
191-
192-
optional arguments:
193-
-h, --help show this help message and exit
194-
--quiet, -q produce less output
195-
--version, -v prints version
196-
--input INPUT, -i INPUT
197-
Docker image archive to process, defaults to stdin
198-
--no-add, -n Don`t add to IPFS, just print directory
199-
--registry REGISTRY, -r REGISTRY
200-
Registry to use when generating pull URL
201-
202-
```
203205

204206
# Changelog
205207

@@ -209,6 +211,7 @@ optional arguments:
209211
* 0.0.4: Support for schema version 2 and docker > 1.10
210212
* 0.0.5: image2ipfs: stop handling archives produced by docker < 1.10, ipfs-registry can still work with all post-1.6.x dockers
211213
* 0.0.6: Deprecate manifest v1. Rewrite image2ipfs-server in golang
214+
* 0.1.0: Rewrite image2ipfs in go: Single binary for client and server
212215

213216
# FAQ
214217

0 commit comments

Comments
 (0)