Xlnk commited on
Commit
7b9f3e3
·
verified ·
1 Parent(s): 7b1148d

Upload 176 files

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. .gitattributes +2 -35
  2. .github/SECURITY.md +16 -0
  3. .github/workflows/test.yml +30 -0
  4. .gitignore +3 -0
  5. Dockerfile +23 -0
  6. Dockerfile.l2 +27 -0
  7. LICENSE +21 -0
  8. api.go +82 -0
  9. config/config.go +78 -0
  10. docker-compose.yml +42 -0
  11. docker/docker.go +546 -0
  12. docker/factory.go +70 -0
  13. docker/factory_mock.go +20 -0
  14. docker/local_cached_factory.go +113 -0
  15. docker/mock.go +160 -0
  16. dockerfiles/dind/.editorconfig +14 -0
  17. dockerfiles/dind/.gitconfig +2 -0
  18. dockerfiles/dind/.inputrc +73 -0
  19. dockerfiles/dind/.profile +6 -0
  20. dockerfiles/dind/.vimrc +6 -0
  21. dockerfiles/dind/Dockerfile +69 -0
  22. dockerfiles/dind/Dockerfile.dind-ee +54 -0
  23. dockerfiles/dind/copy_certs.ps1 +114 -0
  24. dockerfiles/dind/daemon.json +17 -0
  25. dockerfiles/dind/docker-prompt +22 -0
  26. dockerfiles/dind/ee/cert.pem +29 -0
  27. dockerfiles/dind/ee/daemon.json +10 -0
  28. dockerfiles/dind/ee/key.pem +51 -0
  29. dockerfiles/dind/ee/ucp-cert.pem +63 -0
  30. dockerfiles/dind/ee/ucp-key.pem +28 -0
  31. dockerfiles/dind/motd +8 -0
  32. dockerfiles/dind/ssh_config +2 -0
  33. dockerfiles/dind/sudo +5 -0
  34. dockerfiles/dind/ucp-beta.sh +98 -0
  35. dockerfiles/dind/ucp-config.toml +2 -0
  36. dockerfiles/dind/ucp.sh +94 -0
  37. dockerfiles/dind/workshop.lic +1 -0
  38. dockerfiles/k8s/.bashrc +3 -0
  39. dockerfiles/k8s/Dockerfile +44 -0
  40. dockerfiles/k8s/daemon.json +14 -0
  41. dockerfiles/k8s/docker.service +30 -0
  42. dockerfiles/k8s/kubelet.env +6 -0
  43. dockerfiles/k8s/kubelet.service +4 -0
  44. dockerfiles/k8s/kubernetes.repo +7 -0
  45. dockerfiles/k8s/motd +28 -0
  46. dockerfiles/k8s/resolv.conf.override +1 -0
  47. dockerfiles/k8s/systemctl +281 -0
  48. dockerfiles/k8s/tokens.csv +1 -0
  49. dockerfiles/k8s/wrapkubeadm.sh +153 -0
  50. dockerfiles/pwm/.gitconfig +2 -0
.gitattributes CHANGED
@@ -1,35 +1,2 @@
1
- *.7z filter=lfs diff=lfs merge=lfs -text
2
- *.arrow filter=lfs diff=lfs merge=lfs -text
3
- *.bin filter=lfs diff=lfs merge=lfs -text
4
- *.bz2 filter=lfs diff=lfs merge=lfs -text
5
- *.ckpt filter=lfs diff=lfs merge=lfs -text
6
- *.ftz filter=lfs diff=lfs merge=lfs -text
7
- *.gz filter=lfs diff=lfs merge=lfs -text
8
- *.h5 filter=lfs diff=lfs merge=lfs -text
9
- *.joblib filter=lfs diff=lfs merge=lfs -text
10
- *.lfs.* filter=lfs diff=lfs merge=lfs -text
11
- *.mlmodel filter=lfs diff=lfs merge=lfs -text
12
- *.model filter=lfs diff=lfs merge=lfs -text
13
- *.msgpack filter=lfs diff=lfs merge=lfs -text
14
- *.npy filter=lfs diff=lfs merge=lfs -text
15
- *.npz filter=lfs diff=lfs merge=lfs -text
16
- *.onnx filter=lfs diff=lfs merge=lfs -text
17
- *.ot filter=lfs diff=lfs merge=lfs -text
18
- *.parquet filter=lfs diff=lfs merge=lfs -text
19
- *.pb filter=lfs diff=lfs merge=lfs -text
20
- *.pickle filter=lfs diff=lfs merge=lfs -text
21
- *.pkl filter=lfs diff=lfs merge=lfs -text
22
- *.pt filter=lfs diff=lfs merge=lfs -text
23
- *.pth filter=lfs diff=lfs merge=lfs -text
24
- *.rar filter=lfs diff=lfs merge=lfs -text
25
- *.safetensors filter=lfs diff=lfs merge=lfs -text
26
- saved_model/**/* filter=lfs diff=lfs merge=lfs -text
27
- *.tar.* filter=lfs diff=lfs merge=lfs -text
28
- *.tar filter=lfs diff=lfs merge=lfs -text
29
- *.tflite filter=lfs diff=lfs merge=lfs -text
30
- *.tgz filter=lfs diff=lfs merge=lfs -text
31
- *.wasm filter=lfs diff=lfs merge=lfs -text
32
- *.xz filter=lfs diff=lfs merge=lfs -text
33
- *.zip filter=lfs diff=lfs merge=lfs -text
34
- *.zst filter=lfs diff=lfs merge=lfs -text
35
- *tfevents* filter=lfs diff=lfs merge=lfs -text
 
1
+ config/gen_bindata.go linguist-generated
2
+ handlers/www/assets/swarm.png filter=lfs diff=lfs merge=lfs -text
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
.github/SECURITY.md ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Security Policy
2
+
3
+ ## Reporting a Vulnerability
4
+
5
+ If there are any vulnerabilities in this project or in [the playground](https://labs.play-with-docker.com), don't hesitate to _report them_.
6
+
7
+ 1. Write an email to marcosnils (at) gmail.com
8
+ 2. Describe the vulnerability.
9
+
10
+ If you have a fix, that is most welcome -- please attach or summarize it in your message!
11
+
12
+ 3. We will evaluate the vulnerability and, if necessary, release a fix or mitigating steps to address it. We will contact you to let you know the outcome, and will credit you in the report.
13
+
14
+ Please **do not disclose the vulnerability publicly** until a fix is released!
15
+
16
+ 4. Once we have either a) published a fix, or b) declined to address the vulnerability for whatever reason, you are free to publicly disclose it.
.github/workflows/test.yml ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ on:
2
+ push:
3
+ branches:
4
+ - master
5
+ pull_request:
6
+ branches:
7
+ - '**'
8
+
9
+ name: Go
10
+ jobs:
11
+ test:
12
+ strategy:
13
+ fail-fast: false
14
+ matrix:
15
+ os: [ubuntu-latest]
16
+ go_version: ["1.16.0"]
17
+ runs-on: ${{ matrix.os }}
18
+ steps:
19
+ - name: Checkout code
20
+ uses: actions/checkout@v2
21
+ - name: Install Go
22
+ uses: actions/setup-go@v2
23
+ with:
24
+ go-version: ${{ matrix.go_version }}
25
+ - name: Generate
26
+ run: go generate ./...
27
+ - name: Test
28
+ run: go test ./...
29
+ - name: Verify clean commit
30
+ run: test -z "$(git status --porcelain)" || (git status; git diff; false)
.gitignore ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ play-with-docker
2
+ node_modules
3
+ /vendor
Dockerfile ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ FROM golang:1.16
2
+
3
+ COPY . /go/src/github.com/play-with-docker/play-with-docker
4
+
5
+ WORKDIR /go/src/github.com/play-with-docker/play-with-docker
6
+
7
+ RUN ssh-keygen -N "" -t rsa -f /etc/ssh/ssh_host_rsa_key >/dev/null
8
+
9
+ RUN CGO_ENABLED=0 go build -a -installsuffix nocgo -o /go/bin/play-with-docker .
10
+
11
+
12
+ FROM alpine
13
+
14
+ RUN apk --update add ca-certificates
15
+ RUN mkdir -p /app/pwd
16
+
17
+ COPY --from=0 /go/bin/play-with-docker /app/play-with-docker
18
+ COPY --from=0 /etc/ssh/ssh_host_rsa_key /etc/ssh/ssh_host_rsa_key
19
+
20
+ WORKDIR /app
21
+ CMD ["./play-with-docker"]
22
+
23
+ EXPOSE 3000
Dockerfile.l2 ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ FROM golang:1.9
2
+
3
+ # Copy the runtime dockerfile into the context as Dockerfile
4
+ COPY . /go/src/github.com/play-with-docker/play-with-docker
5
+
6
+ WORKDIR /go/src/github.com/play-with-docker/play-with-docker
7
+
8
+
9
+ RUN ssh-keygen -N "" -t rsa -f /etc/ssh/ssh_host_rsa_key >/dev/null
10
+
11
+ WORKDIR /go/src/github.com/play-with-docker/play-with-docker/router/l2
12
+
13
+ RUN CGO_ENABLED=0 go build -a -installsuffix nocgo -o /go/bin/play-with-docker-l2 .
14
+
15
+
16
+ FROM alpine
17
+
18
+ RUN apk --update add ca-certificates
19
+ RUN mkdir /app
20
+
21
+ COPY --from=0 /go/bin/play-with-docker-l2 /app/play-with-docker-l2
22
+ COPY --from=0 /etc/ssh/ssh_host_rsa_key /etc/ssh/ssh_host_rsa_key
23
+
24
+ WORKDIR /app
25
+ CMD ["./play-with-docker-l2", "-ssh_key_path", "/etc/ssh/ssh_host_rsa_key"]
26
+
27
+ EXPOSE 22 53 443 8080
LICENSE ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ MIT License
2
+
3
+ Copyright (c) 2016 Marcos Lilljedhal and Jonathan Leibiusky
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
api.go ADDED
@@ -0,0 +1,82 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ package main
2
+
3
+ import (
4
+ "log"
5
+ "os"
6
+ "time"
7
+
8
+ "github.com/play-with-docker/play-with-docker/config"
9
+ "github.com/play-with-docker/play-with-docker/docker"
10
+ "github.com/play-with-docker/play-with-docker/event"
11
+ "github.com/play-with-docker/play-with-docker/handlers"
12
+ "github.com/play-with-docker/play-with-docker/id"
13
+ "github.com/play-with-docker/play-with-docker/k8s"
14
+ "github.com/play-with-docker/play-with-docker/provisioner"
15
+ "github.com/play-with-docker/play-with-docker/pwd"
16
+ "github.com/play-with-docker/play-with-docker/pwd/types"
17
+ "github.com/play-with-docker/play-with-docker/scheduler"
18
+ "github.com/play-with-docker/play-with-docker/scheduler/task"
19
+ "github.com/play-with-docker/play-with-docker/storage"
20
+ )
21
+
22
+ func main() {
23
+ config.ParseFlags()
24
+
25
+ e := initEvent()
26
+ s := initStorage()
27
+ df := initDockerFactory(s)
28
+ kf := initK8sFactory(s)
29
+
30
+ ipf := provisioner.NewInstanceProvisionerFactory(provisioner.NewWindowsASG(df, s), provisioner.NewDinD(id.XIDGenerator{}, df, s))
31
+ sp := provisioner.NewOverlaySessionProvisioner(df)
32
+
33
+ core := pwd.NewPWD(df, e, s, sp, ipf)
34
+
35
+ tasks := []scheduler.Task{
36
+ task.NewCheckPorts(e, df),
37
+ task.NewCheckSwarmPorts(e, df),
38
+ task.NewCheckSwarmStatus(e, df),
39
+ task.NewCollectStats(e, df, s),
40
+ task.NewCheckK8sClusterStatus(e, kf),
41
+ task.NewCheckK8sClusterExposedPorts(e, kf),
42
+ }
43
+ sch, err := scheduler.NewScheduler(tasks, s, e, core)
44
+ if err != nil {
45
+ log.Fatal("Error initializing the scheduler: ", err)
46
+ }
47
+
48
+ sch.Start()
49
+
50
+ d, err := time.ParseDuration("2h")
51
+ if err != nil {
52
+ log.Fatalf("Cannot parse duration Got: %v", err)
53
+ }
54
+
55
+ playground := types.Playground{Domain: config.PlaygroundDomain, DefaultDinDInstanceImage: "franela/dind", AvailableDinDInstanceImages: []string{"franela/dind"}, AllowWindowsInstances: config.NoWindows, DefaultSessionDuration: d, Extras: map[string]interface{}{"LoginRedirect": "http://localhost:3000"}, Privileged: true}
56
+ if _, err := core.PlaygroundNew(playground); err != nil {
57
+ log.Fatalf("Cannot create default playground. Got: %v", err)
58
+ }
59
+
60
+ handlers.Bootstrap(core, e)
61
+ handlers.Register(nil)
62
+ }
63
+
64
+ func initStorage() storage.StorageApi {
65
+ s, err := storage.NewFileStorage(config.SessionsFile)
66
+ if err != nil && !os.IsNotExist(err) {
67
+ log.Fatal("Error initializing StorageAPI: ", err)
68
+ }
69
+ return s
70
+ }
71
+
72
+ func initEvent() event.EventApi {
73
+ return event.NewLocalBroker()
74
+ }
75
+
76
+ func initDockerFactory(s storage.StorageApi) docker.FactoryApi {
77
+ return docker.NewLocalCachedFactory(s)
78
+ }
79
+
80
+ func initK8sFactory(s storage.StorageApi) k8s.FactoryApi {
81
+ return k8s.NewLocalCachedFactory(s)
82
+ }
config/config.go ADDED
@@ -0,0 +1,78 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ package config
2
+
3
+ import (
4
+ "flag"
5
+ "os"
6
+ "regexp"
7
+
8
+ "github.com/gorilla/securecookie"
9
+
10
+ "golang.org/x/oauth2"
11
+ )
12
+
13
+ const (
14
+ PWDHostnameRegex = "[0-9]{1,3}-[0-9]{1,3}-[0-9]{1,3}-[0-9]{1,3}"
15
+ PortRegex = "[0-9]{1,5}"
16
+ AliasnameRegex = "[0-9|a-z|A-Z|-]*"
17
+ AliasSessionRegex = "[0-9|a-z|A-Z]{8}"
18
+ AliasGroupRegex = "(" + AliasnameRegex + ")-(" + AliasSessionRegex + ")"
19
+ PWDHostPortGroupRegex = "^.*ip(" + PWDHostnameRegex + ")(?:-?(" + PortRegex + "))?(?:\\..*)?$"
20
+ AliasPortGroupRegex = "^.*pwd" + AliasGroupRegex + "(?:-?(" + PortRegex + "))?\\..*$"
21
+ )
22
+
23
+ var (
24
+ NameFilter = regexp.MustCompile(PWDHostPortGroupRegex)
25
+ AliasFilter = regexp.MustCompile(AliasPortGroupRegex)
26
+ )
27
+
28
+ var (
29
+ PortNumber, SessionsFile, PWDContainerName, L2ContainerName, L2Subdomain, HashKey, SSHKeyPath, L2RouterIP, CookieHashKey, CookieBlockKey string
30
+ UseLetsEncrypt, ExternalDindVolume, NoWindows bool
31
+ LetsEncryptCertsDir string
32
+ MaxLoadAvg float64
33
+ ForceTLS bool
34
+ SecureCookie *securecookie.SecureCookie
35
+ AdminToken string
36
+ )
37
+
38
+ // Unsafe enables a number of unsafe features when set. It is principally
39
+ // intended to be used in development. For example, it allows the caller to
40
+ // specify the Docker networks to join.
41
+ var Unsafe bool
42
+
43
+ var PlaygroundDomain string
44
+
45
+ var SegmentId string
46
+
47
+ // TODO move this to a sync map so it can be updated on demand when the configuration for a playground changes
48
+ var Providers = map[string]map[string]*oauth2.Config{}
49
+
50
+ func ParseFlags() {
51
+ flag.StringVar(&LetsEncryptCertsDir, "letsencrypt-certs-dir", "/certs", "Path where let's encrypt certs will be stored")
52
+ flag.BoolVar(&UseLetsEncrypt, "letsencrypt-enable", false, "Enabled let's encrypt tls certificates")
53
+ flag.BoolVar(&ForceTLS, "tls", false, "Use TLS to connect to docker daemons")
54
+ flag.StringVar(&PortNumber, "port", "3000", "Port number")
55
+ flag.StringVar(&SessionsFile, "save", "./pwd/sessions", "Tell where to store sessions file")
56
+ flag.StringVar(&PWDContainerName, "name", "pwd", "Container name used to run PWD (used to be able to connect it to the networks it creates)")
57
+ flag.StringVar(&L2ContainerName, "l2", "l2", "Container name used to run L2 Router")
58
+ flag.StringVar(&L2RouterIP, "l2-ip", "", "Host IP address for L2 router ping response")
59
+ flag.StringVar(&L2Subdomain, "l2-subdomain", "direct", "Subdomain to the L2 Router")
60
+ flag.StringVar(&HashKey, "hash_key", "salmonrosado", "Hash key to use for cookies")
61
+ flag.BoolVar(&NoWindows, "win-disable", false, "Disable windows instances")
62
+ flag.BoolVar(&ExternalDindVolume, "dind-external-volume", false, "Use external dind volume though XFS volume driver")
63
+ flag.Float64Var(&MaxLoadAvg, "maxload", 100, "Maximum allowed load average before failing ping requests")
64
+ flag.StringVar(&SSHKeyPath, "ssh_key_path", "", "SSH Private Key to use")
65
+ flag.StringVar(&CookieHashKey, "cookie-hash-key", "", "Hash key to use to validate cookies")
66
+ flag.StringVar(&CookieBlockKey, "cookie-block-key", "", "Block key to use to encrypt cookies")
67
+
68
+ flag.StringVar(&PlaygroundDomain, "playground-domain", "localhost", "Domain to use for the playground")
69
+ flag.StringVar(&AdminToken, "admin-token", "", "Token to validate admin user for admin endpoints")
70
+
71
+ flag.StringVar(&SegmentId, "segment-id", "", "Segment id to post metrics")
72
+
73
+ flag.BoolVar(&Unsafe, "unsafe", os.Getenv("PWD_UNSAFE") == "true", "Operate in unsafe mode")
74
+
75
+ flag.Parse()
76
+
77
+ SecureCookie = securecookie.New([]byte(CookieHashKey), []byte(CookieBlockKey))
78
+ }
docker-compose.yml ADDED
@@ -0,0 +1,42 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ version: '3.2'
2
+ services:
3
+ haproxy:
4
+ container_name: haproxy
5
+ image: haproxy
6
+ ports:
7
+ - "80:8080"
8
+ volumes:
9
+ - ./haproxy:/usr/local/etc/haproxy
10
+
11
+ pwd:
12
+ # pwd daemon container always needs to be named this way
13
+ container_name: pwd
14
+ # use the latest golang image
15
+ image: golang
16
+ # go to the right place and starts the app
17
+ command: /bin/sh -c 'ssh-keygen -N "" -t rsa -f /etc/ssh/ssh_host_rsa_key >/dev/null; cd /go/src/; if [ -e /runbin/pwd ]; then /runbin/pwd -save /pwd/sessions -name l2; else go run api.go -save /pwd/sessions -name l2; fi'
18
+ environment:
19
+ - APPARMOR_PROFILE=docker-dind
20
+ volumes:
21
+ # since this app creates networks and launches containers, we need to talk to docker daemon
22
+ - /var/run/docker.sock:/var/run/docker.sock
23
+ # mount the box mounted shared folder to the container
24
+ - $PWD:/go/src
25
+ - sessions:/pwd
26
+ l2:
27
+ container_name: l2
28
+ # use the latest golang image
29
+ image: golang
30
+ # go to the right place and starts the app
31
+ command: /bin/sh -c 'ssh-keygen -N "" -t rsa -f /etc/ssh/ssh_host_rsa_key >/dev/null; cd /go/src/router/l2; if [ -e /runbin/l2 ]; then /runbin/l2 -ssh_key_path /etc/ssh/ssh_host_rsa_key -name l2 -save /pwd/networks; else go run l2.go -ssh_key_path /etc/ssh/ssh_host_rsa_key -name l2 -save /pwd/networks; fi'
32
+ volumes:
33
+ - /var/run/docker.sock:/var/run/docker.sock
34
+ - $PWD:/go/src
35
+ - networks:/pwd
36
+ ports:
37
+ - "8022:22"
38
+ - "8053:53"
39
+ - "443:443"
40
+ volumes:
41
+ sessions:
42
+ networks:
docker/docker.go ADDED
@@ -0,0 +1,546 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ package docker
2
+
3
+ import (
4
+ "archive/tar"
5
+ "bytes"
6
+ "context"
7
+ "fmt"
8
+ "io"
9
+ "io/ioutil"
10
+ "log"
11
+ "net"
12
+ "os"
13
+ "strconv"
14
+ "strings"
15
+ "time"
16
+
17
+ "github.com/containerd/containerd/reference"
18
+ "github.com/docker/docker/api/types"
19
+ "github.com/docker/docker/api/types/container"
20
+ "github.com/docker/docker/api/types/network"
21
+ "github.com/docker/docker/api/types/swarm"
22
+ "github.com/docker/docker/api/types/volume"
23
+ "github.com/docker/docker/client"
24
+ "github.com/play-with-docker/play-with-docker/config"
25
+ )
26
+
27
+ const (
28
+ Byte = 1
29
+ Kilobyte = 1024 * Byte
30
+ Megabyte = 1024 * Kilobyte
31
+ )
32
+
33
+ type DockerApi interface {
34
+ GetClient() *client.Client
35
+
36
+ NetworkCreate(id string, opts types.NetworkCreate) error
37
+ NetworkConnect(container, network, ip string) (string, error)
38
+ NetworkInspect(id string) (types.NetworkResource, error)
39
+ NetworkDelete(id string) error
40
+ NetworkDisconnect(containerId, networkId string) error
41
+
42
+ DaemonInfo() (types.Info, error)
43
+ DaemonHost() string
44
+
45
+ GetSwarmPorts() ([]string, []uint16, error)
46
+ GetPorts() ([]uint16, error)
47
+
48
+ ContainerStats(name string) (io.ReadCloser, error)
49
+ ContainerResize(name string, rows, cols uint) error
50
+ ContainerRename(old, new string) error
51
+ ContainerDelete(name string) error
52
+ ContainerCreate(opts CreateContainerOpts) error
53
+ ContainerIPs(id string) (map[string]string, error)
54
+ ExecAttach(instanceName string, command []string, out io.Writer) (int, error)
55
+ Exec(instanceName string, command []string) (int, error)
56
+
57
+ CreateAttachConnection(name string) (net.Conn, error)
58
+ CopyToContainer(containerName, destination, fileName string, content io.Reader) error
59
+ CopyFromContainer(containerName, filePath string) (io.Reader, error)
60
+ SwarmInit(advertiseAddr string) (*SwarmTokens, error)
61
+ SwarmJoin(addr, token string) error
62
+
63
+ ConfigCreate(name string, labels map[string]string, data []byte) error
64
+ ConfigDelete(name string) error
65
+ }
66
+
67
+ type SwarmTokens struct {
68
+ Manager string
69
+ Worker string
70
+ }
71
+
72
+ type docker struct {
73
+ c *client.Client
74
+ }
75
+
76
+ func (d *docker) GetClient() *client.Client {
77
+ return d.c
78
+ }
79
+
80
+ func (d *docker) ConfigCreate(name string, labels map[string]string, data []byte) error {
81
+ config := swarm.ConfigSpec{}
82
+ config.Name = name
83
+ config.Labels = labels
84
+ config.Data = data
85
+ _, err := d.c.ConfigCreate(context.Background(), config)
86
+ return err
87
+ }
88
+ func (d *docker) ConfigDelete(name string) error {
89
+ return d.c.ConfigRemove(context.Background(), name)
90
+ }
91
+
92
+ func (d *docker) NetworkCreate(id string, opts types.NetworkCreate) error {
93
+ _, err := d.c.NetworkCreate(context.Background(), id, opts)
94
+
95
+ if err != nil {
96
+ log.Printf("Starting session err [%s]\n", err)
97
+
98
+ return err
99
+ }
100
+
101
+ return nil
102
+ }
103
+
104
+ func (d *docker) NetworkConnect(containerId, networkId, ip string) (string, error) {
105
+ settings := &network.EndpointSettings{}
106
+ if ip != "" {
107
+ settings.IPAddress = ip
108
+ }
109
+ err := d.c.NetworkConnect(context.Background(), networkId, containerId, settings)
110
+
111
+ if err != nil && !strings.Contains(err.Error(), "already exists") {
112
+ log.Printf("Connection container to network err [%s]\n", err)
113
+
114
+ return "", err
115
+ }
116
+
117
+ // Obtain the IP of the PWD container in this network
118
+ container, err := d.c.ContainerInspect(context.Background(), containerId)
119
+ if err != nil {
120
+ return "", err
121
+ }
122
+
123
+ n, found := container.NetworkSettings.Networks[networkId]
124
+ if !found {
125
+ return "", fmt.Errorf("Container [%s] connected to the network [%s] but couldn't obtain it's IP address", containerId, networkId)
126
+ }
127
+
128
+ return n.IPAddress, nil
129
+ }
130
+
131
+ func (d *docker) NetworkInspect(id string) (types.NetworkResource, error) {
132
+ return d.c.NetworkInspect(context.Background(), id, types.NetworkInspectOptions{})
133
+ }
134
+
135
+ func (d *docker) DaemonInfo() (types.Info, error) {
136
+ return d.c.Info(context.Background())
137
+ }
138
+
139
+ func (d *docker) DaemonHost() string {
140
+ return d.c.DaemonHost()
141
+ }
142
+
143
+ func (d *docker) GetSwarmPorts() ([]string, []uint16, error) {
144
+ hosts := []string{}
145
+ ports := []uint16{}
146
+
147
+ nodesIdx := map[string]string{}
148
+ nodes, nodesErr := d.c.NodeList(context.Background(), types.NodeListOptions{})
149
+ if nodesErr != nil {
150
+ return nil, nil, nodesErr
151
+ }
152
+ for _, n := range nodes {
153
+ nodesIdx[n.ID] = n.Description.Hostname
154
+ hosts = append(hosts, n.Description.Hostname)
155
+ }
156
+
157
+ services, err := d.c.ServiceList(context.Background(), types.ServiceListOptions{})
158
+ if err != nil {
159
+ return nil, nil, err
160
+ }
161
+ for _, service := range services {
162
+ for _, p := range service.Endpoint.Ports {
163
+ ports = append(ports, uint16(p.PublishedPort))
164
+ }
165
+ }
166
+
167
+ return hosts, ports, nil
168
+ }
169
+
170
+ func (d *docker) GetPorts() ([]uint16, error) {
171
+ opts := types.ContainerListOptions{}
172
+ containers, err := d.c.ContainerList(context.Background(), opts)
173
+ if err != nil {
174
+ return nil, err
175
+ }
176
+
177
+ openPorts := []uint16{}
178
+ for _, c := range containers {
179
+ for _, p := range c.Ports {
180
+ // When port is not published on the host docker return public port as 0, so we need to avoid it
181
+ if p.PublicPort != 0 {
182
+ openPorts = append(openPorts, p.PublicPort)
183
+ }
184
+ }
185
+ }
186
+
187
+ return openPorts, nil
188
+ }
189
+
190
+ func (d *docker) ContainerStats(name string) (io.ReadCloser, error) {
191
+ stats, err := d.c.ContainerStats(context.Background(), name, false)
192
+
193
+ return stats.Body, err
194
+ }
195
+
196
+ func (d *docker) ContainerResize(name string, rows, cols uint) error {
197
+ return d.c.ContainerResize(context.Background(), name, types.ResizeOptions{Height: rows, Width: cols})
198
+ }
199
+
200
+ func (d *docker) ContainerRename(old, new string) error {
201
+ return d.c.ContainerRename(context.Background(), old, new)
202
+ }
203
+
204
+ func (d *docker) CreateAttachConnection(name string) (net.Conn, error) {
205
+ ctx := context.Background()
206
+
207
+ conf := types.ContainerAttachOptions{true, true, true, true, "ctrl-^,ctrl-^", true}
208
+ conn, err := d.c.ContainerAttach(ctx, name, conf)
209
+ if err != nil {
210
+ return nil, err
211
+ }
212
+
213
+ return conn.Conn, nil
214
+ }
215
+
216
+ func (d *docker) CopyToContainer(containerName, destination, fileName string, content io.Reader) error {
217
+ contents, err := ioutil.ReadAll(content)
218
+ if err != nil {
219
+ return err
220
+ }
221
+ var buf bytes.Buffer
222
+ t := tar.NewWriter(&buf)
223
+ if err := t.WriteHeader(&tar.Header{Name: fileName, Mode: 0600, Size: int64(len(contents)), ModTime: time.Now()}); err != nil {
224
+ return err
225
+ }
226
+ if _, err := t.Write(contents); err != nil {
227
+ return err
228
+ }
229
+ if err := t.Close(); err != nil {
230
+ return err
231
+ }
232
+ return d.c.CopyToContainer(context.Background(), containerName, destination, &buf, types.CopyToContainerOptions{AllowOverwriteDirWithFile: true, CopyUIDGID: true})
233
+ }
234
+
235
+ func (d *docker) CopyFromContainer(containerName, filePath string) (io.Reader, error) {
236
+ rc, stat, err := d.c.CopyFromContainer(context.Background(), containerName, filePath)
237
+ if err != nil {
238
+ return nil, err
239
+ }
240
+ if stat.Mode.IsDir() {
241
+ return nil, fmt.Errorf("Copying directories is not supported")
242
+ }
243
+ tr := tar.NewReader(rc)
244
+ // advance to the only possible file in the tar archive
245
+ tr.Next()
246
+ return tr, nil
247
+ }
248
+
249
+ func (d *docker) ContainerDelete(name string) error {
250
+ err := d.c.ContainerRemove(context.Background(), name, types.ContainerRemoveOptions{Force: true, RemoveVolumes: true})
251
+ d.c.VolumeRemove(context.Background(), name, true)
252
+ return err
253
+ }
254
+
255
+ type CreateContainerOpts struct {
256
+ Image string
257
+ SessionId string
258
+ ContainerName string
259
+ Hostname string
260
+ ServerCert []byte
261
+ ServerKey []byte
262
+ CACert []byte
263
+ Privileged bool
264
+ HostFQDN string
265
+ Labels map[string]string
266
+ Networks []string
267
+ DindVolumeSize string
268
+ Envs []string
269
+ }
270
+
271
+ func (d *docker) ContainerCreate(opts CreateContainerOpts) (err error) {
272
+ // Make sure directories are available for the new instance container
273
+ containerDir := "/opt/pwd"
274
+ containerCertDir := fmt.Sprintf("%s/certs", containerDir)
275
+
276
+ env := append(opts.Envs, fmt.Sprintf("SESSION_ID=%s", opts.SessionId))
277
+
278
+ // Write certs to container cert dir
279
+ if len(opts.ServerCert) > 0 {
280
+ env = append(env, `DOCKER_TLSCERT=\/opt\/pwd\/certs\/cert.pem`)
281
+ }
282
+ if len(opts.ServerKey) > 0 {
283
+ env = append(env, `DOCKER_TLSKEY=\/opt\/pwd\/certs\/key.pem`)
284
+ }
285
+ if len(opts.CACert) > 0 {
286
+ // if ca cert is specified, verify that clients that connects present a certificate signed by the CA
287
+ env = append(env, `DOCKER_TLSCACERT=\/opt\/pwd\/certs\/ca.pem`)
288
+ }
289
+ if len(opts.ServerCert) > 0 || len(opts.ServerKey) > 0 || len(opts.CACert) > 0 {
290
+ // if any of the certs is specified, enable TLS
291
+ env = append(env, "DOCKER_TLSENABLE=true")
292
+ } else {
293
+ env = append(env, "DOCKER_TLSENABLE=false")
294
+ }
295
+
296
+ h := &container.HostConfig{
297
+ NetworkMode: container.NetworkMode(opts.SessionId),
298
+ Privileged: opts.Privileged,
299
+ AutoRemove: true,
300
+ LogConfig: container.LogConfig{Config: map[string]string{"max-size": "10m", "max-file": "1"}},
301
+ }
302
+
303
+ if os.Getenv("APPARMOR_PROFILE") != "" {
304
+ h.SecurityOpt = []string{fmt.Sprintf("apparmor=%s", os.Getenv("APPARMOR_PROFILE"))}
305
+ }
306
+
307
+ if os.Getenv("STORAGE_SIZE") != "" {
308
+ // assing 10GB size FS for each container
309
+ h.StorageOpt = map[string]string{"size": os.Getenv("STORAGE_SIZE")}
310
+ }
311
+
312
+ var pidsLimit = int64(1000)
313
+ if envLimit := os.Getenv("MAX_PROCESSES"); envLimit != "" {
314
+ if i, err := strconv.Atoi(envLimit); err == nil {
315
+ pidsLimit = int64(i)
316
+ }
317
+ }
318
+ h.Resources.PidsLimit = &pidsLimit
319
+
320
+ if memLimit := os.Getenv("MAX_MEMORY_MB"); memLimit != "" {
321
+ if i, err := strconv.Atoi(memLimit); err == nil {
322
+ h.Resources.Memory = int64(i) * Megabyte
323
+ }
324
+ }
325
+
326
+ t := true
327
+ h.Resources.OomKillDisable = &t
328
+
329
+ env = append(env, fmt.Sprintf("PWD_HOST_FQDN=%s", opts.HostFQDN))
330
+ cf := &container.Config{
331
+ Hostname: opts.Hostname,
332
+ Image: opts.Image,
333
+ Tty: true,
334
+ OpenStdin: true,
335
+ AttachStdin: true,
336
+ AttachStdout: true,
337
+ AttachStderr: true,
338
+ Env: env,
339
+ Labels: opts.Labels,
340
+ }
341
+
342
+ networkConf := &network.NetworkingConfig{
343
+ EndpointsConfig: map[string]*network.EndpointSettings{opts.Networks[0]: &network.EndpointSettings{}},
344
+ }
345
+
346
+ if config.ExternalDindVolume {
347
+ _, err = d.c.VolumeCreate(context.Background(), volume.VolumeCreateBody{
348
+ Driver: "xfsvol",
349
+ DriverOpts: map[string]string{
350
+ "size": opts.DindVolumeSize,
351
+ },
352
+ Name: opts.ContainerName,
353
+ })
354
+ if err != nil {
355
+ return
356
+ }
357
+ h.Binds = []string{fmt.Sprintf("%s:/var/lib/docker", opts.ContainerName)}
358
+
359
+ defer func() {
360
+ if err != nil {
361
+ d.c.VolumeRemove(context.Background(), opts.SessionId, true)
362
+ }
363
+ }()
364
+ }
365
+
366
+ container, err := d.c.ContainerCreate(context.Background(), cf, h, networkConf, opts.ContainerName)
367
+
368
+ if err != nil {
369
+ //if client.IsErrImageNotFound(err) {
370
+ //log.Printf("Unable to find image '%s' locally\n", opts.Image)
371
+ //if err = d.pullImage(context.Background(), opts.Image); err != nil {
372
+ //return "", err
373
+ //}
374
+ //container, err = d.c.ContainerCreate(context.Background(), cf, h, networkConf, opts.ContainerName)
375
+ //if err != nil {
376
+ //return "", err
377
+ //}
378
+ //} else {
379
+ return err
380
+ //}
381
+ }
382
+
383
+ //connect remaining networks if there are any
384
+ if len(opts.Networks) > 1 {
385
+ for _, nid := range opts.Networks {
386
+ err = d.c.NetworkConnect(context.Background(), nid, container.ID, &network.EndpointSettings{})
387
+ if err != nil {
388
+ return
389
+ }
390
+ }
391
+ }
392
+
393
+ if err = d.copyIfSet(opts.ServerCert, "cert.pem", containerCertDir, opts.ContainerName); err != nil {
394
+ return
395
+ }
396
+ if err = d.copyIfSet(opts.ServerKey, "key.pem", containerCertDir, opts.ContainerName); err != nil {
397
+ return
398
+ }
399
+ if err = d.copyIfSet(opts.CACert, "ca.pem", containerCertDir, opts.ContainerName); err != nil {
400
+ return
401
+ }
402
+
403
+ err = d.c.ContainerStart(context.Background(), container.ID, types.ContainerStartOptions{})
404
+ if err != nil {
405
+ return
406
+ }
407
+
408
+ return
409
+ }
410
+
411
+ func (d *docker) ContainerIPs(id string) (map[string]string, error) {
412
+ cinfo, err := d.c.ContainerInspect(context.Background(), id)
413
+ if err != nil {
414
+ return nil, err
415
+ }
416
+
417
+ ips := map[string]string{}
418
+ for networkId, conf := range cinfo.NetworkSettings.Networks {
419
+ ips[networkId] = conf.IPAddress
420
+ }
421
+ return ips, nil
422
+
423
+ }
424
+
425
+ func (d *docker) pullImage(ctx context.Context, image string) error {
426
+ _, err := reference.Parse(image)
427
+ if err != nil {
428
+ return err
429
+ }
430
+
431
+ options := types.ImageCreateOptions{}
432
+
433
+ responseBody, err := d.c.ImageCreate(ctx, image, options)
434
+ if err != nil {
435
+ return err
436
+ }
437
+ _, err = io.Copy(ioutil.Discard, responseBody)
438
+
439
+ return err
440
+ }
441
+
442
+ func (d *docker) copyIfSet(content []byte, fileName, path, containerName string) error {
443
+ if len(content) > 0 {
444
+ return d.CopyToContainer(containerName, path, fileName, bytes.NewReader(content))
445
+ }
446
+ return nil
447
+ }
448
+
449
+ func (d *docker) ExecAttach(instanceName string, command []string, out io.Writer) (int, error) {
450
+ e, err := d.c.ContainerExecCreate(context.Background(), instanceName, types.ExecConfig{Cmd: command, AttachStdout: true, AttachStderr: true, Tty: true})
451
+ if err != nil {
452
+ return 0, err
453
+ }
454
+ resp, err := d.c.ContainerExecAttach(context.Background(), e.ID, types.ExecStartCheck{
455
+ Tty: true,
456
+ })
457
+ if err != nil {
458
+ return 0, err
459
+ }
460
+ io.Copy(out, resp.Reader)
461
+ var ins types.ContainerExecInspect
462
+ for _ = range time.Tick(1 * time.Second) {
463
+ ins, err = d.c.ContainerExecInspect(context.Background(), e.ID)
464
+ if ins.Running {
465
+ continue
466
+ }
467
+ if err != nil {
468
+ return 0, err
469
+ }
470
+ break
471
+ }
472
+ return ins.ExitCode, nil
473
+
474
+ }
475
+
476
+ func (d *docker) Exec(instanceName string, command []string) (int, error) {
477
+ e, err := d.c.ContainerExecCreate(context.Background(), instanceName, types.ExecConfig{Cmd: command})
478
+ if err != nil {
479
+ return 0, err
480
+ }
481
+ err = d.c.ContainerExecStart(context.Background(), e.ID, types.ExecStartCheck{})
482
+ if err != nil {
483
+ return 0, err
484
+ }
485
+ var ins types.ContainerExecInspect
486
+ for _ = range time.Tick(1 * time.Second) {
487
+ ins, err = d.c.ContainerExecInspect(context.Background(), e.ID)
488
+ if ins.Running {
489
+ continue
490
+ }
491
+ if err != nil {
492
+ return 0, err
493
+ }
494
+ break
495
+ }
496
+ return ins.ExitCode, nil
497
+ }
498
+
499
+ func (d *docker) NetworkDisconnect(containerId, networkId string) error {
500
+ err := d.c.NetworkDisconnect(context.Background(), networkId, containerId, true)
501
+
502
+ if err != nil {
503
+ log.Printf("Disconnection of container from network err [%s]\n", err)
504
+
505
+ return err
506
+ }
507
+
508
+ return nil
509
+ }
510
+
511
+ func (d *docker) NetworkDelete(id string) error {
512
+ err := d.c.NetworkRemove(context.Background(), id)
513
+
514
+ if err != nil {
515
+ return err
516
+ }
517
+
518
+ return nil
519
+ }
520
+
521
+ func (d *docker) SwarmInit(advertiseAddr string) (*SwarmTokens, error) {
522
+ req := swarm.InitRequest{AdvertiseAddr: advertiseAddr, ListenAddr: "0.0.0.0:2377"}
523
+ _, err := d.c.SwarmInit(context.Background(), req)
524
+
525
+ if err != nil {
526
+ return nil, err
527
+ }
528
+
529
+ swarmInfo, err := d.c.SwarmInspect(context.Background())
530
+ if err != nil {
531
+ return nil, err
532
+ }
533
+
534
+ return &SwarmTokens{
535
+ Worker: swarmInfo.JoinTokens.Worker,
536
+ Manager: swarmInfo.JoinTokens.Manager,
537
+ }, nil
538
+ }
539
+ func (d *docker) SwarmJoin(addr, token string) error {
540
+ req := swarm.JoinRequest{RemoteAddrs: []string{addr}, JoinToken: token, ListenAddr: "0.0.0.0:2377", AdvertiseAddr: "eth0"}
541
+ return d.c.SwarmJoin(context.Background(), req)
542
+ }
543
+
544
+ func NewDocker(c *client.Client) *docker {
545
+ return &docker{c: c}
546
+ }
docker/factory.go ADDED
@@ -0,0 +1,70 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ package docker
2
+
3
+ import (
4
+ "crypto/tls"
5
+ "fmt"
6
+ "net"
7
+ "net/http"
8
+ "net/url"
9
+ "time"
10
+
11
+ "github.com/docker/docker/api"
12
+ "github.com/docker/docker/client"
13
+ "github.com/docker/go-connections/tlsconfig"
14
+ "github.com/play-with-docker/play-with-docker/pwd/types"
15
+ "github.com/play-with-docker/play-with-docker/router"
16
+ )
17
+
18
+ type FactoryApi interface {
19
+ GetForSession(session *types.Session) (DockerApi, error)
20
+ GetForInstance(instance *types.Instance) (DockerApi, error)
21
+ }
22
+
23
+ func NewClient(instance *types.Instance, proxyHost string) (*client.Client, error) {
24
+ var host string
25
+ var durl string
26
+
27
+ var tlsConfig *tls.Config
28
+ if (len(instance.Cert) > 0 && len(instance.Key) > 0) || instance.Tls {
29
+ host = router.EncodeHost(instance.SessionId, instance.RoutableIP, router.HostOpts{EncodedPort: 2376})
30
+ tlsConfig = tlsconfig.ClientDefault()
31
+ tlsConfig.InsecureSkipVerify = true
32
+ tlsConfig.ServerName = host
33
+ if len(instance.Cert) > 0 && len(instance.Key) > 0 {
34
+ tlsCert, err := tls.X509KeyPair(instance.Cert, instance.Key)
35
+ if err != nil {
36
+ return nil, fmt.Errorf("Could not load X509 key pair: %v. Make sure the key is not encrypted", err)
37
+ }
38
+ tlsConfig.Certificates = []tls.Certificate{tlsCert}
39
+ }
40
+ } else {
41
+ host = router.EncodeHost(instance.SessionId, instance.RoutableIP, router.HostOpts{EncodedPort: 2375})
42
+ }
43
+
44
+ transport := &http.Transport{
45
+ DialContext: (&net.Dialer{
46
+ Timeout: 1 * time.Second,
47
+ KeepAlive: 30 * time.Second,
48
+ }).DialContext,
49
+ MaxIdleConnsPerHost: 5,
50
+ }
51
+
52
+ if tlsConfig != nil {
53
+ transport.TLSClientConfig = tlsConfig
54
+ durl = fmt.Sprintf("https://%s", proxyHost)
55
+ } else {
56
+ transport.Proxy = http.ProxyURL(&url.URL{Host: proxyHost})
57
+ durl = fmt.Sprintf("http://%s", host)
58
+ }
59
+
60
+ cli := &http.Client{
61
+ Transport: transport,
62
+ }
63
+
64
+ dc, err := client.NewClient(durl, api.DefaultVersion, cli, nil)
65
+ if err != nil {
66
+ return nil, fmt.Errorf("Could not connect to DinD docker daemon: %v", err)
67
+ }
68
+
69
+ return dc, nil
70
+ }
docker/factory_mock.go ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ package docker
2
+
3
+ import (
4
+ "github.com/play-with-docker/play-with-docker/pwd/types"
5
+ "github.com/stretchr/testify/mock"
6
+ )
7
+
8
+ type FactoryMock struct {
9
+ mock.Mock
10
+ }
11
+
12
+ func (m *FactoryMock) GetForSession(session *types.Session) (DockerApi, error) {
13
+ args := m.Called(session)
14
+ return args.Get(0).(DockerApi), args.Error(1)
15
+ }
16
+
17
+ func (m *FactoryMock) GetForInstance(instance *types.Instance) (DockerApi, error) {
18
+ args := m.Called(instance)
19
+ return args.Get(0).(DockerApi), args.Error(1)
20
+ }
docker/local_cached_factory.go ADDED
@@ -0,0 +1,113 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ package docker
2
+
3
+ import (
4
+ "context"
5
+ "fmt"
6
+ "log"
7
+ "sync"
8
+ "time"
9
+
10
+ "github.com/docker/docker/client"
11
+ "github.com/play-with-docker/play-with-docker/pwd/types"
12
+ "github.com/play-with-docker/play-with-docker/storage"
13
+ )
14
+
15
+ type localCachedFactory struct {
16
+ rw sync.Mutex
17
+ irw sync.Mutex
18
+ sessionClient DockerApi
19
+ instanceClients map[string]*instanceEntry
20
+ storage storage.StorageApi
21
+ }
22
+
23
+ type instanceEntry struct {
24
+ rw sync.Mutex
25
+ client DockerApi
26
+ }
27
+
28
+ func (f *localCachedFactory) GetForSession(session *types.Session) (DockerApi, error) {
29
+ f.rw.Lock()
30
+ defer f.rw.Unlock()
31
+
32
+ if f.sessionClient != nil {
33
+ if err := f.check(f.sessionClient.GetClient()); err == nil {
34
+ return f.sessionClient, nil
35
+ } else {
36
+ f.sessionClient.GetClient().Close()
37
+ }
38
+ }
39
+
40
+ c, err := client.NewClientWithOpts()
41
+ if err != nil {
42
+ return nil, err
43
+ }
44
+ err = f.check(c)
45
+ if err != nil {
46
+ return nil, err
47
+ }
48
+ d := NewDocker(c)
49
+ f.sessionClient = d
50
+ return f.sessionClient, nil
51
+ }
52
+
53
+ func (f *localCachedFactory) GetForInstance(instance *types.Instance) (DockerApi, error) {
54
+ key := instance.Name
55
+
56
+ f.irw.Lock()
57
+ c, found := f.instanceClients[key]
58
+ if !found {
59
+ c := &instanceEntry{}
60
+ f.instanceClients[key] = c
61
+ }
62
+ c = f.instanceClients[key]
63
+ f.irw.Unlock()
64
+
65
+ c.rw.Lock()
66
+ defer c.rw.Unlock()
67
+
68
+ if c.client != nil {
69
+ if err := f.check(c.client.GetClient()); err == nil {
70
+ return c.client, nil
71
+ } else {
72
+ c.client.GetClient().Close()
73
+ }
74
+ }
75
+
76
+ dc, err := NewClient(instance, "l2:443")
77
+ if err != nil {
78
+ return nil, err
79
+ }
80
+ err = f.check(dc)
81
+ if err != nil {
82
+ return nil, err
83
+ }
84
+ dockerClient := NewDocker(dc)
85
+ c.client = dockerClient
86
+
87
+ return dockerClient, nil
88
+ }
89
+
90
+ func (f *localCachedFactory) check(c *client.Client) error {
91
+ ok := false
92
+ for i := 0; i < 5; i++ {
93
+ _, err := c.Ping(context.Background())
94
+ if err != nil {
95
+ log.Printf("Connection to [%s] has failed, maybe instance is not ready yet, sleeping and retrying in 1 second. Try #%d. Got: %v\n", c.DaemonHost(), i+1, err)
96
+ time.Sleep(time.Second)
97
+ continue
98
+ }
99
+ ok = true
100
+ break
101
+ }
102
+ if !ok {
103
+ return fmt.Errorf("Connection to docker daemon was not established.")
104
+ }
105
+ return nil
106
+ }
107
+
108
+ func NewLocalCachedFactory(s storage.StorageApi) *localCachedFactory {
109
+ return &localCachedFactory{
110
+ instanceClients: make(map[string]*instanceEntry),
111
+ storage: s,
112
+ }
113
+ }
docker/mock.go ADDED
@@ -0,0 +1,160 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ package docker
2
+
3
+ import (
4
+ "io"
5
+ "net"
6
+ "time"
7
+
8
+ "github.com/docker/docker/api/types"
9
+ "github.com/docker/docker/client"
10
+ "github.com/stretchr/testify/mock"
11
+ )
12
+
13
+ type Mock struct {
14
+ mock.Mock
15
+ }
16
+
17
+ func (m *Mock) GetClient() *client.Client {
18
+ args := m.Called()
19
+ return args.Get(0).(*client.Client)
20
+ }
21
+
22
+ func (m *Mock) NetworkCreate(id string, opts types.NetworkCreate) error {
23
+ args := m.Called(id, opts)
24
+ return args.Error(0)
25
+ }
26
+
27
+ func (m *Mock) NetworkConnect(container, network, ip string) (string, error) {
28
+ args := m.Called(container, network, ip)
29
+ return args.String(0), args.Error(1)
30
+ }
31
+
32
+ func (m *Mock) NetworkInspect(id string) (types.NetworkResource, error) {
33
+ args := m.Called(id)
34
+ return args.Get(0).(types.NetworkResource), args.Error(1)
35
+ }
36
+
37
+ func (m *Mock) DaemonInfo() (types.Info, error) {
38
+ args := m.Called()
39
+ return args.Get(0).(types.Info), args.Error(1)
40
+ }
41
+
42
+ func (m *Mock) DaemonHost() string {
43
+ args := m.Called()
44
+ return args.String(0)
45
+ }
46
+
47
+ func (m *Mock) GetSwarmPorts() ([]string, []uint16, error) {
48
+ args := m.Called()
49
+ return args.Get(0).([]string), args.Get(1).([]uint16), args.Error(2)
50
+ }
51
+
52
+ func (m *Mock) GetPorts() ([]uint16, error) {
53
+ args := m.Called()
54
+ return args.Get(0).([]uint16), args.Error(1)
55
+ }
56
+ func (m *Mock) ContainerStats(name string) (io.ReadCloser, error) {
57
+ args := m.Called(name)
58
+ return args.Get(0).(io.ReadCloser), args.Error(1)
59
+ }
60
+ func (m *Mock) ContainerResize(name string, rows, cols uint) error {
61
+ args := m.Called(name, rows, cols)
62
+ return args.Error(0)
63
+ }
64
+ func (m *Mock) ContainerRename(old, new string) error {
65
+ args := m.Called(old, new)
66
+ return args.Error(0)
67
+ }
68
+ func (m *Mock) CreateAttachConnection(name string) (net.Conn, error) {
69
+ args := m.Called(name)
70
+ return args.Get(0).(net.Conn), args.Error(1)
71
+ }
72
+ func (m *Mock) CopyToContainer(containerName, destination, fileName string, content io.Reader) error {
73
+ args := m.Called(containerName, destination, fileName, content)
74
+ return args.Error(0)
75
+ }
76
+
77
+ func (m *Mock) CopyFromContainer(containerName, filePath string) (io.Reader, error) {
78
+ args := m.Called(containerName, filePath)
79
+ return args.Get(0).(io.Reader), args.Error(1)
80
+ }
81
+ func (m *Mock) ContainerDelete(id string) error {
82
+ args := m.Called(id)
83
+ return args.Error(0)
84
+ }
85
+ func (m *Mock) ContainerCreate(opts CreateContainerOpts) error {
86
+ args := m.Called(opts)
87
+ return args.Error(0)
88
+ }
89
+ func (m *Mock) ContainerIPs(id string) (map[string]string, error) {
90
+ args := m.Called(id)
91
+ return args.Get(0).(map[string]string), args.Error(1)
92
+ }
93
+
94
+ func (m *Mock) ExecAttach(instanceName string, command []string, out io.Writer) (int, error) {
95
+ args := m.Called(instanceName, command, out)
96
+ return args.Int(0), args.Error(1)
97
+ }
98
+ func (m *Mock) NetworkDisconnect(containerId, networkId string) error {
99
+ args := m.Called(containerId, networkId)
100
+ return args.Error(0)
101
+ }
102
+ func (m *Mock) NetworkDelete(id string) error {
103
+ args := m.Called(id)
104
+ return args.Error(0)
105
+ }
106
+ func (m *Mock) Exec(instanceName string, command []string) (int, error) {
107
+ args := m.Called(instanceName, command)
108
+ return args.Int(0), args.Error(1)
109
+ }
110
+ func (m *Mock) SwarmInit(advertiseAddr string) (*SwarmTokens, error) {
111
+ args := m.Called(advertiseAddr)
112
+ return args.Get(0).(*SwarmTokens), args.Error(1)
113
+ }
114
+ func (m *Mock) SwarmJoin(addr, token string) error {
115
+ args := m.Called(addr, token)
116
+ return args.Error(0)
117
+ }
118
+ func (m *Mock) ConfigCreate(name string, labels map[string]string, data []byte) error {
119
+ args := m.Called(name, labels, data)
120
+ return args.Error(0)
121
+ }
122
+ func (m *Mock) ConfigDelete(name string) error {
123
+ args := m.Called(name)
124
+ return args.Error(0)
125
+ }
126
+
127
+ type MockConn struct {
128
+ }
129
+
130
+ func (m *MockConn) Read(b []byte) (n int, err error) {
131
+ return len(b), nil
132
+ }
133
+
134
+ func (m *MockConn) Write(b []byte) (n int, err error) {
135
+ return len(b), nil
136
+ }
137
+
138
+ func (m *MockConn) Close() error {
139
+ return nil
140
+ }
141
+
142
+ func (m *MockConn) LocalAddr() net.Addr {
143
+ return &net.IPAddr{}
144
+ }
145
+
146
+ func (m *MockConn) RemoteAddr() net.Addr {
147
+ return &net.IPAddr{}
148
+ }
149
+
150
+ func (m *MockConn) SetDeadline(t time.Time) error {
151
+ return nil
152
+ }
153
+
154
+ func (m *MockConn) SetReadDeadline(t time.Time) error {
155
+ return nil
156
+ }
157
+
158
+ func (m *MockConn) SetWriteDeadline(t time.Time) error {
159
+ return nil
160
+ }
dockerfiles/dind/.editorconfig ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # top-most EditorConfig file
2
+ root = true
3
+
4
+ # Unix-style newlines with a newline ending every file
5
+ [*]
6
+ end_of_line = lf
7
+ insert_final_newline = true
8
+ charset = utf-8
9
+ indent_style = space
10
+ indent_size = 4
11
+
12
+ # Tab indentation (no size specified)
13
+ [{Makefile,*.go}]
14
+ indent_style = tab
dockerfiles/dind/.gitconfig ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ [url "https://"]
2
+ insteadOf = git://
dockerfiles/dind/.inputrc ADDED
@@ -0,0 +1,73 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # /etc/inputrc - global inputrc for libreadline
2
+ # See readline(3readline) and `info rluserman' for more information.
3
+
4
+ # Be 8 bit clean.
5
+ set input-meta on
6
+ set output-meta on
7
+
8
+ # To allow the use of 8bit-characters like the german umlauts, uncomment
9
+ # the line below. However this makes the meta key not work as a meta key,
10
+ # which is annoying to those which don't need to type in 8-bit characters.
11
+
12
+ # set convert-meta off
13
+
14
+ # try to enable the application keypad when it is called. Some systems
15
+ # need this to enable the arrow keys.
16
+ # set enable-keypad on
17
+
18
+ # see /usr/share/doc/bash/inputrc.arrows for other codes of arrow keys
19
+
20
+ # do not bell on tab-completion
21
+ # set bell-style none
22
+ # set bell-style visible
23
+
24
+ # some defaults / modifications for the emacs mode
25
+ $if mode=emacs
26
+
27
+ # allow the use of the Home/End keys
28
+ "\e[1~": beginning-of-line
29
+ "\e[4~": end-of-line
30
+
31
+ # allow the use of the Delete/Insert keys
32
+ "\e[3~": delete-char
33
+ "\e[2~": quoted-insert
34
+
35
+ # mappings for "page up" and "page down" to step to the beginning/end
36
+ # of the history
37
+ # "\e[5~": beginning-of-history
38
+ # "\e[6~": end-of-history
39
+
40
+ # alternate mappings for "page up" and "page down" to search the history
41
+ # "\e[5~": history-search-backward
42
+ # "\e[6~": history-search-forward
43
+
44
+ # mappings for Ctrl-left-arrow and Ctrl-right-arrow for word moving
45
+ "\e[1;5C": forward-word
46
+ "\e[1;5D": backward-word
47
+ "\e[5C": forward-word
48
+ "\e[5D": backward-word
49
+ "\e\e[C": forward-word
50
+ "\e\e[D": backward-word
51
+
52
+ $if term=rxvt
53
+ "\e[7~": beginning-of-line
54
+ "\e[8~": end-of-line
55
+ "\eOc": forward-word
56
+ "\eOd": backward-word
57
+ $endif
58
+
59
+ # for non RH/Debian xterm, can't hurt for RH/Debian xterm
60
+ # "\eOH": beginning-of-line
61
+ # "\eOF": end-of-line
62
+
63
+ # for freebsd console
64
+ # "\e[H": beginning-of-line
65
+ # "\e[F": end-of-line
66
+
67
+ $endif
68
+
69
+ # faster completion
70
+ set show-all-if-ambiguous on
71
+
72
+ "\e[A": history-search-backward
73
+ "\e[B": history-search-forward
dockerfiles/dind/.profile ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ export PS1='\e[1m\e[31m[\h] \e[32m($(docker-prompt)) \e[34m\u@$(hostname -i)\e[35m \w\e[0m\n$ '
2
+ alias vi='vim'
3
+ export PATH=$PATH:/root/go/bin
4
+ export DOCKER_HOST=""
5
+ cat /etc/motd
6
+ echo $BASHPID > /var/run/cwd
dockerfiles/dind/.vimrc ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ syntax on
2
+ set autoindent
3
+ set expandtab
4
+ set number
5
+ set shiftwidth=2
6
+ set softtabstop=2
dockerfiles/dind/Dockerfile ADDED
@@ -0,0 +1,69 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ARG VERSION=docker:dind
2
+ FROM ${VERSION}
3
+
4
+ RUN apk add --no-cache py-pip python3-dev libffi-dev openssl-dev git tmux apache2-utils vim build-base gettext-dev curl bash-completion bash util-linux jq openssh openssl tree \
5
+ && ln -s /usr/local/bin/docker /usr/bin/docker
6
+
7
+ ENV GOPATH /root/go
8
+ ENV IPTABLES_LEGACY /usr/local/sbin/.iptables-legacy/
9
+ ENV PATH $IPTABLES_LEGACY:$GOPATH:$PATH
10
+
11
+
12
+ ENV DOCKER_TLS_CERTDIR=""
13
+ ENV DOCKER_CLI_EXPERIMENTAL=enabled
14
+
15
+ # Install compose
16
+ ENV COMPOSE_VERSION=2.18.1
17
+ RUN mkdir -p /usr/lib/docker/cli-plugins \
18
+ && curl -LsS https://github.com/docker/compose/releases/download/v$COMPOSE_VERSION/docker-compose-linux-x86_64 -o /usr/lib/docker/cli-plugins/docker-compose \
19
+ && chmod +x /usr/lib/docker/cli-plugins/docker-compose
20
+
21
+
22
+ # Install scout
23
+ ENV SCOUT_VERSION=1.0.9
24
+ RUN wget -O /tmp/scout.tar.gz https://github.com/docker/scout-cli/releases/download/v1.0.9/docker-scout_1.0.9_linux_amd64.tar.gz \
25
+ && tar -xvf /tmp/scout.tar.gz docker-scout -C /usr/local/bin \
26
+ && chmod +x /usr/local/bin/docker-scout \
27
+ && ln -s $(which docker-scout) /usr/lib/docker/cli-plugins \
28
+ && rm /tmp/scout.tar.gz
29
+
30
+
31
+
32
+ # Add bash completion and set bash as default shell
33
+ RUN curl -sS https://raw.githubusercontent.com/docker/cli/refs/heads/master/contrib/completion/bash/docker -o /etc/bash_completion.d/docker \
34
+ && sed -i "s/ash/bash/" /etc/passwd
35
+
36
+ # Replace modprobe with a no-op to get rid of spurious warnings
37
+ # (note: we can't just symlink to /bin/true because it might be busybox)
38
+ RUN rm /sbin/modprobe && echo '#!/bin/true' >/sbin/modprobe && chmod +x /sbin/modprobe
39
+
40
+ # Install a nice vimrc file and prompt (by soulshake)
41
+ COPY ["docker-prompt", "sudo", "/usr/local/bin/"]
42
+ COPY [".vimrc", ".profile", ".inputrc", ".gitconfig", "./root/"]
43
+ COPY ["motd", "/etc/motd"]
44
+ COPY ["daemon.json", "/etc/docker/"]
45
+
46
+
47
+ # Move to our home
48
+ WORKDIR /root
49
+
50
+ # Setup certs and ssh keys
51
+ RUN mkdir -p /var/run/pwd/certs && mkdir -p /var/run/pwd/uploads \
52
+ && ssh-keygen -N "" -t ed25519 -f /etc/ssh/ssh_host_ed25519_key >/dev/null \
53
+ && mkdir ~/.ssh && ssh-keygen -N "" -t ed25519 -f ~/.ssh/id_rsa \
54
+ && cat ~/.ssh/id_rsa.pub > ~/.ssh/authorized_keys
55
+
56
+ # Remove IPv6 alias for localhost and start docker in the background ...
57
+ CMD cat /etc/hosts >/etc/hosts.bak && \
58
+ sed 's/^::1.*//' /etc/hosts.bak > /etc/hosts && \
59
+ sed -i "s/\PWD_IP_ADDRESS/$PWD_IP_ADDRESS/" /etc/docker/daemon.json && \
60
+ sed -i "s/\DOCKER_TLSENABLE/$DOCKER_TLSENABLE/" /etc/docker/daemon.json && \
61
+ sed -i "s/\DOCKER_TLSCACERT/$DOCKER_TLSCACERT/" /etc/docker/daemon.json && \
62
+ sed -i "s/\DOCKER_TLSCERT/$DOCKER_TLSCERT/" /etc/docker/daemon.json && \
63
+ sed -i "s/\DOCKER_TLSKEY/$DOCKER_TLSKEY/" /etc/docker/daemon.json && \
64
+ mount -t securityfs none /sys/kernel/security && \
65
+ echo "root:root" | chpasswd &> /dev/null && \
66
+ /usr/sbin/sshd -o PermitRootLogin=yes -o PrintMotd=no 2>/dev/null && \
67
+ dockerd &>/docker.log & \
68
+ while true ; do script -q -c "/bin/bash -l" /dev/null ; done
69
+ # ... and then put a shell in the foreground, restarting it if it exits
dockerfiles/dind/Dockerfile.dind-ee ADDED
@@ -0,0 +1,54 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ARG VERSION=franela/docker:ubuntu-19.03ee
2
+ #ARG VERSION=franela/docker:18.09.2-ee-dind
3
+
4
+ FROM ${VERSION}
5
+
6
+ RUN apt-get update \
7
+ && apt-get install -y git tmux python-pip apache2-utils vim curl jq bash-completion screen tree zip \
8
+ && rm -rf /var/lib/apt/lists/*
9
+
10
+ # Add kubectl client
11
+ RUN curl -LO https://storage.googleapis.com/kubernetes-release/release/v1.11.7/bin/linux/amd64/kubectl \
12
+ && chmod +x ./kubectl \
13
+ && mv ./kubectl /usr/local/bin/kubectl
14
+
15
+ ENV COMPOSE_VERSION=1.22.0
16
+
17
+ RUN pip install docker-compose==${COMPOSE_VERSION}
18
+ RUN curl -L https://github.com/docker/machine/releases/download/${MACHINE_VERSION}/docker-machine-Linux-x86_64 \
19
+ -o /usr/bin/docker-machine && chmod +x /usr/bin/docker-machine
20
+
21
+
22
+ # Install a nice vimrc file and prompt (by soulshake)
23
+ COPY ["docker-prompt", "sudo", "ucp-beta.sh", "/usr/local/bin/"]
24
+ COPY [".vimrc",".profile", ".inputrc", ".gitconfig", "workshop_beta.lic", "ucp-config.toml", "./root/"]
25
+ COPY ["motd", "/etc/motd"]
26
+ COPY ["ee/daemon.json", "/etc/docker/"]
27
+ COPY ["ee/cert.pem", "ee/key.pem", "/opt/pwd/certs/"]
28
+ COPY ["ee/ucp-key.pem", "./root/key.pem"]
29
+ COPY ["ee/ucp-cert.pem", "./root/cert.pem"]
30
+
31
+ # Move to our home
32
+ WORKDIR /root
33
+
34
+ # Setup certs and uploads folders
35
+ RUN mkdir -p /opt/pwd/certs /opt/pwd/uploads
36
+
37
+ VOLUME ["/var/lib/kubelet"]
38
+
39
+ # Remove IPv6 alias for localhost and start docker in the background ...
40
+ CMD cat /etc/hosts >/etc/hosts.bak && \
41
+ sed 's/^::1.*//' /etc/hosts.bak > /etc/hosts && \
42
+ sed -i "s/\PWD_IP_ADDRESS/$PWD_IP_ADDRESS/" /etc/docker/daemon.json && \
43
+ sed -i "s/\DOCKER_TLSENABLE/$DOCKER_TLSENABLE/" /etc/docker/daemon.json && \
44
+ sed -i "s/\DOCKER_TLSCACERT/$DOCKER_TLSCACERT/" /etc/docker/daemon.json && \
45
+ sed -i "s/\DOCKER_TLSCERT/$DOCKER_TLSCERT/" /etc/docker/daemon.json && \
46
+ sed -i "s/\DOCKER_TLSKEY/$DOCKER_TLSKEY/" /etc/docker/daemon.json && \
47
+ mount -t securityfs none /sys/kernel/security && \
48
+ mount --make-rshared / && \
49
+ #mount --make-rshared -t tmpfs tmpfs /run && \
50
+ #mount --make-rshared /var/lib/kubelet && \
51
+ #mount --make-rshared /var/lib/docker && \
52
+ dockerd > /docker.log 2>&1 & \
53
+ while true ; do script -q -c "/bin/bash -l" /dev/null ; done
54
+ # ... and then put a shell in the foreground, restarting it if it exits
dockerfiles/dind/copy_certs.ps1 ADDED
@@ -0,0 +1,114 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ param (
2
+ [Parameter(Mandatory = $true)]
3
+ [string] $Node,
4
+ [Parameter(Mandatory = $true)]
5
+ [string] $SessionId,
6
+ [Parameter(Mandatory = $true)]
7
+ [string] $FQDN
8
+ )
9
+
10
+
11
+ function GetDirectUrlFromIp ($ip) {
12
+ $ip_dash=$ip -replace "\.","-"
13
+ $url="https://ip${ip_dash}-${SessionId}.direct.${FQDN}"
14
+ return $url
15
+ }
16
+
17
+ function WaitForUrl ($url) {
18
+ write-host $url
19
+ do {
20
+ try{
21
+ invoke-webrequest -UseBasicParsing -uri $url | Out-Null
22
+ } catch {}
23
+ $status = $?
24
+ sleep 1
25
+ } until($status)
26
+ }
27
+
28
+ function GetNodeRoutableIp ($nodeName) {
29
+ $JQFilter='.instances[] | select (.hostname == \"{0}\") | .routable_ip' -f $nodeName
30
+ $rip = (invoke-webrequest -UseBasicParsing -uri "https://$FQDN/sessions/$SessionId").Content | jq -r $JQFilter
31
+
32
+ IF([string]::IsNullOrEmpty($rip)) {
33
+ Write-Host "Could not fetch IP for node $nodeName"
34
+ exit 1
35
+ }
36
+ return $rip
37
+ }
38
+
39
+ function Set-UseUnsafeHeaderParsing
40
+ {
41
+ param(
42
+ [Parameter(Mandatory,ParameterSetName='Enable')]
43
+ [switch]$Enable,
44
+
45
+ [Parameter(Mandatory,ParameterSetName='Disable')]
46
+ [switch]$Disable
47
+ )
48
+
49
+ $ShouldEnable = $PSCmdlet.ParameterSetName -eq 'Enable'
50
+
51
+ $netAssembly = [Reflection.Assembly]::GetAssembly([System.Net.Configuration.SettingsSection])
52
+
53
+ if($netAssembly)
54
+ {
55
+ $bindingFlags = [Reflection.BindingFlags] 'Static,GetProperty,NonPublic'
56
+ $settingsType = $netAssembly.GetType('System.Net.Configuration.SettingsSectionInternal')
57
+
58
+ $instance = $settingsType.InvokeMember('Section', $bindingFlags, $null, $null, @())
59
+
60
+ if($instance)
61
+ {
62
+ $bindingFlags = 'NonPublic','Instance'
63
+ $useUnsafeHeaderParsingField = $settingsType.GetField('useUnsafeHeaderParsing', $bindingFlags)
64
+
65
+ if($useUnsafeHeaderParsingField)
66
+ {
67
+ $useUnsafeHeaderParsingField.SetValue($instance, $ShouldEnable)
68
+ }
69
+ }
70
+ }
71
+ }
72
+
73
+
74
+ $ProgressPreference = 'SilentlyContinue'
75
+ $ErrorActionPreference = 'Stop'
76
+
77
+ Set-UseUnsafeHeaderParsing -Enable
78
+
79
+ Start-Transcript -path ("C:\{0}.log" -f $MyInvocation.MyCommand.Name) -append
80
+
81
+ add-type @"
82
+ using System.Net;
83
+ using System.Security.Cryptography.X509Certificates;
84
+
85
+ public class IDontCarePolicy : ICertificatePolicy {
86
+ public IDontCarePolicy() {}
87
+ public bool CheckValidationResult(
88
+ ServicePoint sPoint, X509Certificate cert,
89
+ WebRequest wRequest, int certProb) {
90
+ return true;
91
+ }
92
+ }
93
+ "@
94
+
95
+ [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
96
+
97
+ [System.Net.ServicePointManager]::CertificatePolicy = new-object IDontCarePolicy
98
+
99
+
100
+ $dtr_ip = GetNodeRoutableIp $Node
101
+ $dtr_url = GetDirectUrlFromIp $dtr_ip
102
+ $dtr_hostname = $dtr_url -replace "https://",""
103
+
104
+ WaitForUrl "${dtr_url}/ca"
105
+
106
+ invoke-webrequest -UseBasicParsing -uri "$dtr_url/ca" -o c:\ca.crt
107
+
108
+ $cert = new-object System.Security.Cryptography.X509Certificates.X509Certificate2 c:\ca.crt
109
+ $store = new-object System.Security.Cryptography.X509Certificates.X509Store('Root','localmachine')
110
+ $store.Open('ReadWrite')
111
+ $store.Add($cert)
112
+ $store.Close()
113
+
114
+ Stop-Transcript
dockerfiles/dind/daemon.json ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "experimental": true,
3
+ "debug": true,
4
+ "log-level": "info",
5
+ "registry-mirrors": ["https://mirror.gcr.io"],
6
+ "insecure-registries": [
7
+ "127.0.0.1"
8
+ ],
9
+ "hosts": [
10
+ "unix:///var/run/docker.sock",
11
+ "tcp://0.0.0.0:2375"
12
+ ],
13
+ "tls": DOCKER_TLSENABLE,
14
+ "tlscacert": "DOCKER_TLSCACERT",
15
+ "tlscert": "DOCKER_TLSCERT",
16
+ "tlskey": "DOCKER_TLSKEY"
17
+ }
dockerfiles/dind/docker-prompt ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ #!/bin/sh
3
+ case "$DOCKER_HOST" in
4
+ *:3376)
5
+ echo swarm
6
+ ;;
7
+ *:2376)
8
+ echo $DOCKER_MACHINE_NAME
9
+ ;;
10
+ *:2375)
11
+ echo $DOCKER_MACHINE_NAME
12
+ ;;
13
+ *:55555)
14
+ echo $DOCKER_MACHINE_NAME
15
+ ;;
16
+ "")
17
+ echo local
18
+ ;;
19
+ *)
20
+ echo unknown
21
+ ;;
22
+ esac
dockerfiles/dind/ee/cert.pem ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ -----BEGIN CERTIFICATE-----
2
+ MIIE9jCCAt6gAwIBAgIQSCiXatddwed3bL9M9bierjANBgkqhkiG9w0BAQsFADAO
3
+ MQwwCgYDVQQKEwNVQ1AwHhcNMTcwOTE1MjAzMzAwWhcNMjAwODMwMjAzMzAwWjAO
4
+ MQwwCgYDVQQKEwNVQ1AwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCq
5
+ prmPRweArtZQ6HHDeYCSC3WxQOy6hakc3VZa6JEldbEoVjOc7MqZNPvTIp8b/W8H
6
+ O10ibEGZ03vyeq10UsiFQiYmdhn1SqEilZnFSo892PSpGaN7VO325uUnIccJqc3O
7
+ 0YOdvNCdp9roZZ/K7z9nuC37cLy6+Lq2oLr1WYAxncJHedUi3LQCC+2qEBIVL+md
8
+ 9yE8amFrYbDhbNqmIcAJ2KmkqBPa0Pa+Qe1FxqQI5zJOT5rOJgF3JbWeqFpm0Zjx
9
+ CPTt0cPY4lyQ2U9lyMXJmS4+R0wekkZXywaU1mJi3JJIlMSBMWmWoTrx5mLVWOLv
10
+ u44hYerfOmN+ImXRWq4NAPLi4722/OLzCmFn81fdUHOFyxg2Tr23b6I6sMyUfLJ0
11
+ lqS+thJ7N/tcQe3nTeQm9dcruDbJpjJQrQkjq9CFFsxNEXBT6EFMRp8oDutOAyHf
12
+ guVeqdH5kz6vprNiLfSTqqZSEeQokRkHTyxpZ4grBBCiocsAxm8yLNqhcg3w44CN
13
+ 9G/3pylgu7xYSEXHYnnlxsk0MHxDFZ4NTo0UBuyIuozoePIS63GvsyBsBzKzO/RZ
14
+ NsnPm3klZ4QnT3dIe0eRtCyu/prRmEMD/zC20fRcAuiG7jyV9NB/9mbLeDjAAngW
15
+ 1UhrWpAMiObQZN4h5+ofc0EXFHVvOWaqBmYXlNlEeQIDAQABo1AwTjAOBgNVHQ8B
16
+ Af8EBAMCA6gwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMBMAwGA1UdEwEB
17
+ /wQCMAAwDwYDVR0RBAgwBocEfwAAATANBgkqhkiG9w0BAQsFAAOCAgEAFT1PFimD
18
+ KGg8fVjuUO9IXf12LA7c+M6Eltyz22Ffxgopl1eHi4xHEfU94ueUAmODrag7Rc4E
19
+ VmvrMFIsuFrX/xYjiu2gpHPOP2nQjNRAwKDU0gr2bZ+y98EBtlYO/aFMmYCxJr7B
20
+ 6esyA7I/cwLTxaNoTh67VTdPhfDmuEshoQn7Mtop38suevU5YBMTmUl7cp8bVdib
21
+ j7UkTq0oRKmAchMAz3W0TgGw9ZKJzU6zEck/3Csz5RWlTI9HV7R7J8aGEIeHGf/i
22
+ G+tfg0T8h+rQPkyCic5DIYuQzZ/P9pfJkedZuQU/mu0U/0IsNdkv9NX/4RQazu/Q
23
+ OzQ71FOO2HR/S3hcLzS1Iy2zrHbARwji/Sr95gVE1Z4QCK2xSvyy9aqzHwRfc4SX
24
+ AzaJhkACCnY7VDK6WJW7jnfkYco+l0tczDkyPjE7h3wP35tCuAZAvGkcrIbBL4oR
25
+ 8bnwYAOqiG0cPBmFDBYW7v19qIspw5XDjfMu4YEHon7pYdiKK0Brf0iL+Ep4b1oB
26
+ 8uvAysbc2Z/gIj1AsfnwSnrzcvzO6H1oCye277cSn2Z/ebiBaQi+kR3mubX96aPy
27
+ bFc9Xb11/y0Y7kYmJ3ifHDJkWerpz5bWEm2KDq1qsFRH9zUMEVfJAXThITawqfuG
28
+ 3UBYWv8RePLnRbbnPuSaO9slNCoKl3NLqyk=
29
+ -----END CERTIFICATE-----
dockerfiles/dind/ee/daemon.json ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "experimental": true,
3
+ "debug": true,
4
+ "log-level": "info",
5
+ "insecure-registries": ["127.0.0.1"],
6
+ "hosts": ["unix:///var/run/docker.sock", "tcp://0.0.0.0:2376"],
7
+ "tls": true,
8
+ "tlscert": "/opt/pwd/certs/cert.pem",
9
+ "tlskey": "/opt/pwd/certs/key.pem"
10
+ }
dockerfiles/dind/ee/key.pem ADDED
@@ -0,0 +1,51 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ -----BEGIN RSA PRIVATE KEY-----
2
+ MIIJJwIBAAKCAgEAqqa5j0cHgK7WUOhxw3mAkgt1sUDsuoWpHN1WWuiRJXWxKFYz
3
+ nOzKmTT70yKfG/1vBztdImxBmdN78nqtdFLIhUImJnYZ9UqhIpWZxUqPPdj0qRmj
4
+ e1Tt9ublJyHHCanNztGDnbzQnafa6GWfyu8/Z7gt+3C8uvi6tqC69VmAMZ3CR3nV
5
+ Ity0AgvtqhASFS/pnfchPGpha2Gw4WzapiHACdippKgT2tD2vkHtRcakCOcyTk+a
6
+ ziYBdyW1nqhaZtGY8Qj07dHD2OJckNlPZcjFyZkuPkdMHpJGV8sGlNZiYtySSJTE
7
+ gTFplqE68eZi1Vji77uOIWHq3zpjfiJl0VquDQDy4uO9tvzi8wphZ/NX3VBzhcsY
8
+ Nk69t2+iOrDMlHyydJakvrYSezf7XEHt503kJvXXK7g2yaYyUK0JI6vQhRbMTRFw
9
+ U+hBTEafKA7rTgMh34LlXqnR+ZM+r6azYi30k6qmUhHkKJEZB08saWeIKwQQoqHL
10
+ AMZvMizaoXIN8OOAjfRv96cpYLu8WEhFx2J55cbJNDB8QxWeDU6NFAbsiLqM6Hjy
11
+ Eutxr7MgbAcyszv0WTbJz5t5JWeEJ093SHtHkbQsrv6a0ZhDA/8wttH0XALohu48
12
+ lfTQf/Zmy3g4wAJ4FtVIa1qQDIjm0GTeIefqH3NBFxR1bzlmqgZmF5TZRHkCAwEA
13
+ AQKCAgBDSNmBFJBwvH7kB8JTQGThMIOHEAJGyMyVBPA3h9sy2eSv8s0G4pY/MhTY
14
+ ep4hext7znw6RlTXQfts79HUO4+0exBvucEiZfqCmFm44Fz6FcDhq6o5xpLM9t0D
15
+ QN4pgToUgadTWk8m2jgFyYvnh82IJ6Z5rUm8rrVvrJAKjO9uoLUpWXAf/sU6yVk7
16
+ 5Ho8wFdsYTRJjeg7XplPSIwtVMFTIIpC0cKCVEH1YikbiebDW+UJ23k+Lt4FDGk/
17
+ 1UFPqPSUlON9oWeG7DlzIzua9j6F7k+9Xn80zpfNpc9CgATq1e0XkRCpn8HyEkAb
18
+ gKsXU6SmwVyY7PKecXcpFIbwtMBK2zTG4VrmgsjwptK1S8lbqYftQeTxvNYdhjxA
19
+ gdkBG5qIBkLcr8m796V2fDtJ6wvsVi+yDh+H7T8/vZuB9iaHJ3L1v36WiTODLTFW
20
+ /OlgfimiBXuK8Z1EiB6+w522TdmhKOiWfjHdl7JSzsOla5i5cbcdeaD4AUzlmvGZ
21
+ RCBE9Cd7RWGmDxnWz4NWFepwSfnOOQI9W95QkcRgwH61Y2axcdio0xJpQnUXiKHH
22
+ rHhPTW0eDD7yoIqqKKK3evCOxpbJy6M/+fVqNZYWEfJ0cb7+Ska6aW3rUv8aeYFj
23
+ xzitqKuL/0nFKpeppAkvXvoZf/mM0QtG+lgUHgOngwweYrrkwQKCAQEA3JtXFZDQ
24
+ mIfkv0mAiwV5QbzQ63OxkO0MtPqSq50I8F6S+fIz+ILhxbMjcGq5dCbnJCFGJqn3
25
+ 7PXrT6nFXZ8j2/dcXmtxala2VAAq+GyA0TY/DQ6seTaKhsLq50vnzMXHT0pU8s/2
26
+ 4n7euf66lzQ1ByKrqXZCAyNajUXPoL37HFgFtCrEJlvi//K8x+tHr3QgF4Si8l31
27
+ A1HLq2+KbppWXzc//knanstsCIxPvEelV0GZn3r5opiOczS30rYo87wKI9aCRgLZ
28
+ GEKrMwlNVwwhScJd4msEYMsXUUxzDcNr5oi+iQmEDJpBKd98+3/Sp9XWVXUbik9a
29
+ QfOvUcQMfDc1pwKCAQEAxgeiaYBb369Z6CW7rC3b3YnwOBJVK23PYcpN2DtnhRRI
30
+ ARZgZBhwYKxDQ3djXZCiPEVtwO4WO8fCcY0GUFP2aVWuaokGjk1gNFwN6F046OdY
31
+ WGETEe7AUCLuuwAv7Aqqug3Y6bxCtPGN3MNHT8qjTH99EMHx8L2+0UiIXnQreGmH
32
+ VL/HEnpfDDZK4nfrwxdJOSueGdyOlflUIpDgmScIbKvIsyKhB2UstFBsCuDzhfE/
33
+ a0VWDnZHgZPA/JhyhRy5eL9QGOqsdnzSxgvEbOyCR5p2jtO9otFw9fxpxF7uA0Yq
34
+ EBye0gidmnF/FKDNK0iggtk34LTrDv2fz4tclXM43wKCAQBY79NC4XgHFjoVGBfX
35
+ dCR3aRy8346Fg9uslpxMzWlOJoKQe6GSHYnRvy+ZYZ1Ug16KBVQXwEwwXtA39JSZ
36
+ 8s9tHaNCeYRmv4CQCuVH885XCcyPggvsbh2YyLoU91gDCPUaNThcD5VTqJw4VcZ5
37
+ sNV0A/k6v29LfpRCAhP7lLvIqH/cK6WaZU71qrGK04K57FIHyTQ8C778UJyQh85C
38
+ WrxZdJe696FIhXAPXinDGQtCSzMYxWYgs+ox7d3x9/g4kuVvn0oz2XAWRMJqN+TT
39
+ JBPDfbWF02kXcKj84Jo9wTwd26Ec9BYlUobUz8G+TsDpYt8e4rBwqR8VGZ3jk+sI
40
+ pOVfAoIBAA78xO33KPzk6IkJUgrV7a32opeby5Zd2TQte3bCCDOqNUjfyKvKrbaj
41
+ UvPoNTz/lUe6eXQAkO41UCIH6lJqCFwwf+LQPA7JDF7qGKNdatE1sRn/PtI8n5Fx
42
+ E2BTw0y6AfHS2nfWJ7ZKEdKDdQI08+b2PyDljMoLkkWEl82OPTv/wJ5JZWegm1Dx
43
+ SvmY2d8KBCCvjGeoqaHwHM4A6P6uVZTj62yjUkyc+6Up8QNhwwyAFayosrqleQP1
44
+ isWTRBeO9PqOgCFioWrWR511hog33iRNLGvi2pdYApSbZeXWyWy2Arj1cY+z1zm5
45
+ HUUSZnTAKmW8yt3W03Nu/olWossszUECggEAD+dqDccmWF30yg82mxIMPb8pMV27
46
+ +ciQssiibGmhFvPcIfzish9FunXqLG7q+4M4M+O4WQ9unuaTH+z9TU7w3Foo4Xdf
47
+ GePuwmZdpuYxClHAsNALuKWEJcjfFOdETLkAbk81+ghtyFblkPPI82wofs4K8OII
48
+ 1KPPDKoxeXmKXVF1UmOJX1KFyMnEjv0+Z1GrHnNV4703cNTMpDybaGpHsE77Vqd0
49
+ ToZY9VG9eDLzaB6n5emSyFGBG73WQFU4EbLKjEBxtthgu8J9b17x96eF1NGZsEl1
50
+ wEJvZpg7v6wyHK5XcYpwLY19+0khtvXwA7KKEr+sHqzF6arIqhl5hDLDAQ==
51
+ -----END RSA PRIVATE KEY-----
dockerfiles/dind/ee/ucp-cert.pem ADDED
@@ -0,0 +1,63 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ -----BEGIN CERTIFICATE-----
2
+ MIIGPDCCBSSgAwIBAgISA4MIK4JV9npV+QdQS7wVa48rMA0GCSqGSIb3DQEBCwUA
3
+ MEoxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MSMwIQYDVQQD
4
+ ExpMZXQncyBFbmNyeXB0IEF1dGhvcml0eSBYMzAeFw0xODAzMzEyMTQ3MjZaFw0x
5
+ ODA2MjkyMTQ3MjZaMDQxMjAwBgNVBAMMKSouZGlyZWN0LmJldGEtaHlicmlkLnBs
6
+ YXktd2l0aC1kb2NrZXIuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC
7
+ AQEA6PQCi9Rqr7Ka1KXSGCfBQVzgPyx/hh+uST1dz7PDw2epghYyaqNByaQEVKNR
8
+ 3ubPvOoASzhdJ1dZdyUzKUoU/jm8hgVK7HHdQDpFEX60az+r4Xo32R6WirG5+GXd
9
+ hU3M0yRzbu0zZx7eVZognP/HcXJDhuf16hiHKmCr6MYXV4JY9xLMxExZOTB4fpGA
10
+ Loiyvn2OEZAhREhiSX+6n4x7KJga8gYn/0f89o7up1DYQSwev+gQgRjTGlo1xrgu
11
+ Oztekc3ydvbhGv7aL7Uj/zqPcVvXnDfnioQV7kEDcz8gupFyV7gZKolR1G8IQJdm
12
+ TaYHguzFXF5Q3lKVWx19/CSZ8wIDAQABo4IDMDCCAywwDgYDVR0PAQH/BAQDAgWg
13
+ MB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAMBgNVHRMBAf8EAjAAMB0G
14
+ A1UdDgQWBBTVloZoUI5vKAN+D1PTgtYBgU184zAfBgNVHSMEGDAWgBSoSmpjBH3d
15
+ uubRObemRWXv86jsoTBvBggrBgEFBQcBAQRjMGEwLgYIKwYBBQUHMAGGImh0dHA6
16
+ Ly9vY3NwLmludC14My5sZXRzZW5jcnlwdC5vcmcwLwYIKwYBBQUHMAKGI2h0dHA6
17
+ Ly9jZXJ0LmludC14My5sZXRzZW5jcnlwdC5vcmcvMDQGA1UdEQQtMCuCKSouZGly
18
+ ZWN0LmJldGEtaHlicmlkLnBsYXktd2l0aC1kb2NrZXIuY29tMIH+BgNVHSAEgfYw
19
+ gfMwCAYGZ4EMAQIBMIHmBgsrBgEEAYLfEwEBATCB1jAmBggrBgEFBQcCARYaaHR0
20
+ cDovL2Nwcy5sZXRzZW5jcnlwdC5vcmcwgasGCCsGAQUFBwICMIGeDIGbVGhpcyBD
21
+ ZXJ0aWZpY2F0ZSBtYXkgb25seSBiZSByZWxpZWQgdXBvbiBieSBSZWx5aW5nIFBh
22
+ cnRpZXMgYW5kIG9ubHkgaW4gYWNjb3JkYW5jZSB3aXRoIHRoZSBDZXJ0aWZpY2F0
23
+ ZSBQb2xpY3kgZm91bmQgYXQgaHR0cHM6Ly9sZXRzZW5jcnlwdC5vcmcvcmVwb3Np
24
+ dG9yeS8wggEDBgorBgEEAdZ5AgQCBIH0BIHxAO8AdQDbdK/uyynssf7KPnFtLOW5
25
+ qrs294Rxg8ddnU83th+/ZAAAAWJ+PniYAAAEAwBGMEQCIDngZdWcYWY0fPfUGTqX
26
+ /Vt2qx+PRN5DN+m13TnA37e2AiBHIi5kMSxlvKNc3xzuJrvt/RKaj9xsBLmc8+uW
27
+ ckaEdAB2ACk8UZZUyDlluqpQ/FgH1Ldvv1h6KXLcpMMM9OVFR/R4AAABYn4+eLUA
28
+ AAQDAEcwRQIhAMkf8SYdt1egjzBE6nzOrY+f4WMS/N6XWN+gFl0mQIkhAiBn9+GG
29
+ 0XbLw33+WNJLUkau2ZdTo5kTw2qdUXdYpWJwrDANBgkqhkiG9w0BAQsFAAOCAQEA
30
+ TAl62gFi+2l/yLItjNIrXeWh2ICH/epjeWlmF+rAb7Sb4iz9U8fsNBdDBQh25xJo
31
+ 6nLOlS2NG0hdUScylCYyGJZe6PeQvGO+qSLDamXf1DvXWvzbmQOCUkejgD7Uwbol
32
+ 5huuCAKoW4SsiaMku0J3545MEQx4Q5cPetsPawaByY5sgr2GZJzgM7lvtzr4hKWg
33
+ x5QAns/bmcqe9LCJ2NLcgArliYu6dOHtS62kB7/Dz2DQRtCvpV553RaBe4k9Ruwl
34
+ 0ndHvjEC5OWa5sW1hwow5W3PC7Db7s0zqpt63EITkhrUOqtqtkwOMYBAkFIIe1eR
35
+ T5fSFAdirKUOt5GnRJ40qw==
36
+ -----END CERTIFICATE-----
37
+ -----BEGIN CERTIFICATE-----
38
+ MIIEkjCCA3qgAwIBAgIQCgFBQgAAAVOFc2oLheynCDANBgkqhkiG9w0BAQsFADA/
39
+ MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT
40
+ DkRTVCBSb290IENBIFgzMB4XDTE2MDMxNzE2NDA0NloXDTIxMDMxNzE2NDA0Nlow
41
+ SjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUxldCdzIEVuY3J5cHQxIzAhBgNVBAMT
42
+ GkxldCdzIEVuY3J5cHQgQXV0aG9yaXR5IFgzMIIBIjANBgkqhkiG9w0BAQEFAAOC
43
+ AQ8AMIIBCgKCAQEAnNMM8FrlLke3cl03g7NoYzDq1zUmGSXhvb418XCSL7e4S0EF
44
+ q6meNQhY7LEqxGiHC6PjdeTm86dicbp5gWAf15Gan/PQeGdxyGkOlZHP/uaZ6WA8
45
+ SMx+yk13EiSdRxta67nsHjcAHJyse6cF6s5K671B5TaYucv9bTyWaN8jKkKQDIZ0
46
+ Z8h/pZq4UmEUEz9l6YKHy9v6Dlb2honzhT+Xhq+w3Brvaw2VFn3EK6BlspkENnWA
47
+ a6xK8xuQSXgvopZPKiAlKQTGdMDQMc2PMTiVFrqoM7hD8bEfwzB/onkxEz0tNvjj
48
+ /PIzark5McWvxI0NHWQWM6r6hCm21AvA2H3DkwIDAQABo4IBfTCCAXkwEgYDVR0T
49
+ AQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAYYwfwYIKwYBBQUHAQEEczBxMDIG
50
+ CCsGAQUFBzABhiZodHRwOi8vaXNyZy50cnVzdGlkLm9jc3AuaWRlbnRydXN0LmNv
51
+ bTA7BggrBgEFBQcwAoYvaHR0cDovL2FwcHMuaWRlbnRydXN0LmNvbS9yb290cy9k
52
+ c3Ryb290Y2F4My5wN2MwHwYDVR0jBBgwFoAUxKexpHsscfrb4UuQdf/EFWCFiRAw
53
+ VAYDVR0gBE0wSzAIBgZngQwBAgEwPwYLKwYBBAGC3xMBAQEwMDAuBggrBgEFBQcC
54
+ ARYiaHR0cDovL2Nwcy5yb290LXgxLmxldHNlbmNyeXB0Lm9yZzA8BgNVHR8ENTAz
55
+ MDGgL6AthitodHRwOi8vY3JsLmlkZW50cnVzdC5jb20vRFNUUk9PVENBWDNDUkwu
56
+ Y3JsMB0GA1UdDgQWBBSoSmpjBH3duubRObemRWXv86jsoTANBgkqhkiG9w0BAQsF
57
+ AAOCAQEA3TPXEfNjWDjdGBX7CVW+dla5cEilaUcne8IkCJLxWh9KEik3JHRRHGJo
58
+ uM2VcGfl96S8TihRzZvoroed6ti6WqEBmtzw3Wodatg+VyOeph4EYpr/1wXKtx8/
59
+ wApIvJSwtmVi4MFU5aMqrSDE6ea73Mj2tcMyo5jMd6jmeWUHK8so/joWUoHOUgwu
60
+ X4Po1QYz+3dszkDqMp4fklxBwXRsW10KXzPMTZ+sOPAveyxindmjkW8lGy+QsRlG
61
+ PfZ+G6Z6h7mjem0Y+iWlkYcV4PIWL1iwBi8saCbGS5jN2p8M+X+Q7UNKEkROb3N6
62
+ KOqkqm57TH2H3eDJAkSnh6/DNFu0Qg==
63
+ -----END CERTIFICATE-----
dockerfiles/dind/ee/ucp-key.pem ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ -----BEGIN PRIVATE KEY-----
2
+ MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDo9AKL1GqvsprU
3
+ pdIYJ8FBXOA/LH+GH65JPV3Ps8PDZ6mCFjJqo0HJpARUo1He5s+86gBLOF0nV1l3
4
+ JTMpShT+ObyGBUrscd1AOkURfrRrP6vhejfZHpaKsbn4Zd2FTczTJHNu7TNnHt5V
5
+ miCc/8dxckOG5/XqGIcqYKvoxhdXglj3EszETFk5MHh+kYAuiLK+fY4RkCFESGJJ
6
+ f7qfjHsomBryBif/R/z2ju6nUNhBLB6/6BCBGNMaWjXGuC47O16RzfJ29uEa/tov
7
+ tSP/Oo9xW9ecN+eKhBXuQQNzPyC6kXJXuBkqiVHUbwhAl2ZNpgeC7MVcXlDeUpVb
8
+ HX38JJnzAgMBAAECggEAVqm4bMa4bea3HRcXYu8fQS7JKhdm1cHhd9PBm6yXzpE5
9
+ CXEyjmNv7RD8n3Qm2BLsA67WLyWn2iPv35hSQTETQETAcudzKSVvFx7WZRzLB/8m
10
+ 9XofXsG3ZZ+avONAlwALjB1KaGEMN3fPZO8y5NVvIDBPGNggr1cyqbxPGAjh1Cav
11
+ Laqki0rdPfr3FhxTyPBdmBFDcaMLc77Yl/7rmQJRYWb1qe+g4SEG4xXmEYpcpSUz
12
+ zDJZAkY5XAO5cHU5EoKgKJedVBNxqAaRtaisO9yv+CKMqD83hAWhXqeK1bSphghs
13
+ 2qIkzNe134ZNUBbmK2FDsAbiPMHNcMKuI4ljfb78iQKBgQD5oZ/uzaYTt6ZQQzKq
14
+ rQFA2DxSlBt4Ewae5n6JYzw0hIjRf7LvitZF9zKXcMkHP2QcL+5RiibyJ6ohGypa
15
+ jpDP+m5e0B5tS6gEgFzBnrXWbjnrDxUR5Qj0lKg3uuOXw8OdwNxn+MulKkIfGyTW
16
+ pCu7G1nh/kltwvN87s4cJycwnwKBgQDu5XUyIcok8nxcBwtxu3zFdtdNn+P4Yq1a
17
+ W2sUEUEJUDwcUZqksPIxQhG/SMEEtBqii+EJj3nAlaWItBgTE37mzKGyKv16ZiM1
18
+ hr+Rlv5AURxER+Eo4JLFqULZKwMaDlXDrFdV2ulF+6SXWOqKrp4/6sPYxtxHmKfs
19
+ oBnXq/4yLQKBgCQFl5+NG2cC/EPevoP0fRbPXT0JVEFqdW0ek6ndoQVvDpM0myyH
20
+ 202zUyCZTNj348lRfVFU3zPYV2t5kQ4KPolUePLDk3BwF2m24CusbE7qDv+FaKPx
21
+ ae5pOTD5jfgLbsHn36Y9N5240FvOve0fOZRBaSH8YLovBJXFnAZh+/y/AoGALZzQ
22
+ CJddAjruNZ/+tmNmykkLiL2riERG9waXZkh5E28nWvzVuvYx9+e2fcBFYkGFCF4O
23
+ xIWJaJTp+zTvl8zUIPsXMG524UTZGiI1N3YN63fRHtRekDB4tZbAtbg5qmLsSyT/
24
+ s9vNSFhor6EBfyMiAfAwHpaxflYOUearqHslWK0CgYEAzi/B0azCOaDqzpp6RhAL
25
+ rhTRFfu2HR8wN8EJLOSbBbUnlSSJHdnHJBwyyXe3shD/rETLV8dHx+6/k47e1l2d
26
+ MUlsad/dOKQyL2pY7UodBzPJkIkmwknDnKzioGety8Tb98oUSTQ8oHfHMuRBOie9
27
+ mq1MSTuZyZtsdSXnFhH3qNc=
28
+ -----END PRIVATE KEY-----
dockerfiles/dind/motd ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ ###############################################################
2
+ # WARNING!!!! #
3
+ # This is a sandbox environment. Using personal credentials #
4
+ # is HIGHLY! discouraged. Any consequences of doing so are #
5
+ # completely the user's responsibilites. #
6
+ # #
7
+ # The PWD team. #
8
+ ###############################################################
dockerfiles/dind/ssh_config ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ Host *
2
+ StrictHostKeyChecking no
dockerfiles/dind/sudo ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ #!/usr/bin/env bash
2
+
3
+ # This is shim to help with the case were pasted commands from a readme assume you are not root. Since this isto be run by root, it should effectively be a dummy command that allows the parameters to pass through.
4
+
5
+ exec "$@"
dockerfiles/dind/ucp-beta.sh ADDED
@@ -0,0 +1,98 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/bin/bash
2
+
3
+ set -e
4
+
5
+ function wait_for_url {
6
+ # Wait for docker daemon to be ready
7
+ while ! curl -k -sS $1 > /dev/null; do
8
+ sleep 1;
9
+ done
10
+ }
11
+
12
+ function deploy_ucp {
13
+ wait_for_url "https://localhost:2376"
14
+
15
+ docker config create com.docker.ucp.config $HOME/ucp-config.toml
16
+
17
+ docker run --rm -i --name ucp \
18
+ -v /var/run/docker.sock:/var/run/docker.sock \
19
+ docker/ucp:3.2.3 install --debug --force-insecure-tcp --skip-cloud-provider-check \
20
+ --san *.direct.${PWD_HOST_FQDN} \
21
+ --license $(cat $HOME/workshop_beta.lic) \
22
+ --swarm-port 2375 \
23
+ --existing-config \
24
+ --admin-username admin \
25
+ --admin-password admin1234
26
+
27
+ rm $HOME/workshop_beta.lic $HOME/ucp-config.toml
28
+ echo "Finished deploying UCP"
29
+ }
30
+
31
+ function get_instance_ip {
32
+ ip -o -4 a s eth1 | awk '{print $4}' | cut -d '/' -f1
33
+ }
34
+
35
+ function get_node_routable_ip {
36
+ curl -sS https://${PWD_HOST_FQDN}/sessions/${SESSION_ID} | jq -r '.instances[] | select(.hostname == "'$1'") | .routable_ip'
37
+ }
38
+
39
+ function get_direct_url_from_ip {
40
+ local ip_dash="${1//./-}"
41
+ local url="https://ip${ip_dash}-${SESSION_ID}.direct.${PWD_HOST_FQDN}"
42
+ echo $url
43
+ }
44
+
45
+ function deploy_dtr {
46
+ if [ $# -lt 1 ]; then
47
+ echo "DTR node hostname"
48
+ return
49
+ fi
50
+
51
+
52
+ local dtr_ip=$(get_node_routable_ip $1)
53
+ local ucp_ip=$(get_instance_ip)
54
+
55
+ local dtr_url=$(get_direct_url_from_ip $dtr_ip)
56
+ local ucp_url=$(get_direct_url_from_ip $ucp_ip)
57
+
58
+ docker run -i --rm docker/dtr:2.7.3 install \
59
+ --dtr-external-url $dtr_url \
60
+ --ucp-node $1 \
61
+ --ucp-username admin \
62
+ --ucp-password admin1234 \
63
+ --ucp-insecure-tls \
64
+ --ucp-url $ucp_url
65
+ }
66
+
67
+ function setup_dtr_certs {
68
+ if [ $# -lt 1 ]; then
69
+ echo "DTR node hostname is missing"
70
+ return
71
+ fi
72
+
73
+
74
+ local dtr_ip=$(get_node_routable_ip $1)
75
+ local dtr_url=$(get_direct_url_from_ip $dtr_ip)
76
+ local dtr_hostname="${dtr_url/https:\/\/}"
77
+
78
+ wait_for_url "$dtr_url/ca"
79
+
80
+ curl -kfsSL $dtr_url/ca -o /usr/local/share/ca-certificates/$dtr_hostname.crt
81
+ update-ca-certificates
82
+ }
83
+
84
+
85
+ case "$1" in
86
+ deploy)
87
+ deploy_ucp
88
+ deploy_dtr $2
89
+ setup_dtr_certs $2
90
+ ;;
91
+ setup-certs)
92
+ setup_dtr_certs $2
93
+ ;;
94
+ *)
95
+ echo "Illegal option $1"
96
+ ;;
97
+ esac
98
+
dockerfiles/dind/ucp-config.toml ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ [cluster_config]
2
+ custom_kubelet_flags = ["--http-check-frequency=20s", "--containerized=false"]
dockerfiles/dind/ucp.sh ADDED
@@ -0,0 +1,94 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/bin/bash
2
+
3
+ set -e
4
+
5
+ function wait_for_url {
6
+ # Wait for docker daemon to be ready
7
+ while ! curl -k -sS $1 > /dev/null; do
8
+ sleep 1;
9
+ done
10
+ }
11
+
12
+ function deploy_ucp {
13
+ wait_for_url "https://localhost:2376"
14
+ docker run --rm -i --name ucp \
15
+ -v /var/run/docker.sock:/var/run/docker.sock \
16
+ docker/ucp:3.2.3 install --debug --force-insecure-tcp --skip-cloud-provider-check \
17
+ --san *.direct.${PWD_HOST_FQDN} \
18
+ --license $(cat $HOME/workshop_beta.lic) \
19
+ --swarm-port 2375 \
20
+ --admin-username admin \
21
+ --admin-password admin1234
22
+
23
+ rm $HOME/workshop_beta.lic
24
+ echo "Finished deploying UCP"
25
+ }
26
+
27
+ function get_instance_ip {
28
+ ip -o -4 a s eth1 | awk '{print $4}' | cut -d '/' -f1
29
+ }
30
+
31
+ function get_node_routable_ip {
32
+ curl -sS https://${PWD_HOST_FQDN}/sessions/${SESSION_ID} | jq -r '.instances[] | select(.hostname == "'$1'") | .routable_ip'
33
+ }
34
+
35
+ function get_direct_url_from_ip {
36
+ local ip_dash="${1//./-}"
37
+ local url="https://ip${ip_dash}-${SESSION_ID}.direct.${PWD_HOST_FQDN}"
38
+ echo $url
39
+ }
40
+
41
+ function deploy_dtr {
42
+ if [ $# -lt 1 ]; then
43
+ echo "DTR node hostname"
44
+ return
45
+ fi
46
+
47
+
48
+ local dtr_ip=$(get_node_routable_ip $1)
49
+ local ucp_ip=$(get_instance_ip)
50
+
51
+ local dtr_url=$(get_direct_url_from_ip $dtr_ip)
52
+ local ucp_url=$(get_direct_url_from_ip $ucp_ip)
53
+
54
+ docker run -i --rm docker/dtr:2.7.3 install \
55
+ --dtr-external-url $dtr_url \
56
+ --ucp-node $1 \
57
+ --ucp-username admin \
58
+ --ucp-password admin1234 \
59
+ --ucp-insecure-tls \
60
+ --ucp-url $ucp_url
61
+ }
62
+
63
+ function setup_dtr_certs {
64
+ if [ $# -lt 1 ]; then
65
+ echo "DTR node hostname is missing"
66
+ return
67
+ fi
68
+
69
+
70
+ local dtr_ip=$(get_node_routable_ip $1)
71
+ local dtr_url=$(get_direct_url_from_ip $dtr_ip)
72
+ local dtr_hostname="${dtr_url/https:\/\/}"
73
+
74
+ wait_for_url "$dtr_url/ca"
75
+
76
+ curl -kfsSL $dtr_url/ca -o /usr/local/share/ca-certificates/$dtr_hostname.crt
77
+ update-ca-certificates
78
+ }
79
+
80
+
81
+ case "$1" in
82
+ deploy)
83
+ deploy_ucp
84
+ deploy_dtr $2
85
+ setup_dtr_certs $2
86
+ ;;
87
+ setup-certs)
88
+ setup_dtr_certs $2
89
+ ;;
90
+ *)
91
+ echo "Illegal option $1"
92
+ ;;
93
+ esac
94
+
dockerfiles/dind/workshop.lic ADDED
@@ -0,0 +1 @@
 
 
1
+ {"key_id":"B3T_Uirjs-tpcGd4Tql8HL--kDo1iTOUaVUFNMhEXM1Z","private_key":"RbtCEoNZ4OBu-yIHNM1mGCJ6R_4SxF-ThghAd-I3b6_N","authorization":"ewogICAicGF5bG9hZCI6ICJleUpsZUhCcGNtRjBhVzl1SWpvaU1qQXhPUzB3TkMweU5GUXhPRG93TkRvek5Gb2lMQ0owYjJ0bGJpSTZJbU16U1VnMllWSjFWak00WjBWSVIwWXRVV1l0ZGxGM2MwMHdlR05vYnpoWE4xSklPRzFLYVRaT1VUUTlJaXdpYldGNFJXNW5hVzVsY3lJNk1UQXNJbk5qWVc1dWFXNW5SVzVoWW14bFpDSTZkSEoxWlN3aWJHbGpaVzV6WlZSNWNHVWlPaUpQWm1ac2FXNWxJaXdpZEdsbGNpSTZJbEJ5YjJSMVkzUnBiMjRpZlEiLAogICAic2lnbmF0dXJlcyI6IFsKICAgICAgewogICAgICAgICAiaGVhZGVyIjogewogICAgICAgICAgICAiandrIjogewogICAgICAgICAgICAgICAiZSI6ICJBUUFCIiwKICAgICAgICAgICAgICAgImtleUlEIjogIko3TEQ6NjdWUjpMNUhaOlU3QkE6Mk80Rzo0QUwzOk9GMk46SkhHQjpFRlRIOjVDVlE6TUZFTzpBRUlUIiwKICAgICAgICAgICAgICAgImtpZCI6ICJKN0xEOjY3VlI6TDVIWjpVN0JBOjJPNEc6NEFMMzpPRjJOOkpIR0I6RUZUSDo1Q1ZROk1GRU86QUVJVCIsCiAgICAgICAgICAgICAgICJrdHkiOiAiUlNBIiwKICAgICAgICAgICAgICAgIm4iOiAieWRJeS1sVTdvN1BjZVktNC1zLUNRNU9FZ0N5RjhDeEljUUlXdUs4NHBJaVpjaVk2NzMweUNZbndMU0tUbHctVTZVQ19RUmVXUmlvTU5ORTVEczVUWUVYYkdHNm9sbTJxZFdiQndjQ2ctMlVVSF9PY0I5V3VQNmdSUEhwTUZNc3hEeld3dmF5OEpVdUhnWVVMVXBtMUl2LW1xN2xwNW5RX1J4clQwS1pSQVFUWUxFTUVmR3dtM2hNT19nZUxQUy1oZ0tQdElIbGtnNl9XY294VEdvS1A3OWRfd2FIWXhHTmw3V2hTbmVpQlN4YnBiUUFLazIxbGc3OThYYjd2WnlFQVRETXJSUjlNZUU2QWRqNUhKcFkzQ295UkFQQ21hS0dSQ0s0dW9aU29JdTBoRlZsS1VQeWJidzAwMEdPLXdhMktOOFV3Z0lJbTBpNUkxdVc5R2txNHpqQnk1emhncXVVWGJHOWJXUEFPWXJxNVFhODFEeEdjQmxKeUhZQXAtRERQRTlUR2c0elltWGpKbnhacUhFZHVHcWRldlo4WE1JMHVrZmtHSUkxNHdVT2lNSUlJclhsRWNCZl80Nkk4Z1FXRHp4eWNaZV9KR1gtTEF1YXlYcnlyVUZlaFZOVWRaVWw5d1hOYUpCLWthQ3F6NVF3YVI5M3NHdy1RU2Z0RDBOdkxlN0N5T0gtRTZ2ZzZTdF9OZVR2Z3Y4WW5oQ2lYSWxaOEhPZkl3TmU3dEVGX1VjejVPYlB5a20zdHlsck5VanQwVnlBbXR0YWNWSTJpR2loY1VQcm1rNGxWSVo3VkRfTFNXLWk3eW9TdXJ0cHNQWGNlMnBLRElvMzBsSkdoT18zS1VtbDJTVVpDcXpKMXlFbUtweXNINUhEVzljc0lGQ0EzZGVBamZaVXZON1UiCiAgICAgICAgICAgIH0sCiAgICAgICAgICAgICJhbGciOiAiUlMyNTYiCiAgICAgICAgIH0sCiAgICAgICAgICJzaWduYXR1cmUiOiAid2xrQUhLd0l1TUs5Y0N3YUdINVB1MW50dGNkLVk0SkNsRnpLeTZtcmJlTzR3eXFOenpwUi16TG4tMlhsYnJGZTdlczYtSklSREhmNzBGR3JRZl9MZEc3QVQ4bC1HRXVoUk1SaF8xVTlXd1BkOGdsWnNFem44VFUyeGtzU3lkWEw2WER3TUlqMHJUMFdpQm43T29YcEc0ZGJrUGgwLWxfY1VKQnphQzlwbEZ3ZXdmdF9Ocl80a0FpcUlNa3FJZHdQaU5XOVc4NERPUFdpZ2FrcTZTTnRtMVpqT2E1UG1ldHUydk1iUGpnTzFZM19tUVFsUldpakRwRUR1Rzl1dl9yNDFsN1I2LTdKQTB6SGpvdVVqdkxDREdIMUQ3eUxnR1RFMTlXN2FMRHI4ZE5FeXBjdi1vQzVmb3pqM19ISjUyWXVDS0RnazJzb3Y5YVFYOHhNTW5DWGU4Y3JIYjlEVG05eVcyd09FN0kxYVZLYXRKbjZrSGprM1FSWGVNbnRNQnJ6TGlzanBjZnlBYzdGNlc1YnBTSUtXaUQtd2o5QTRlY0FPbFNxc0NBS3lkaWxnR2lqQTNPY1dOZHhvV0NhV1MzaXFvakFBTE1JNHlsOFlpdG50ckVMVFNuUDFFS08wTGFaaTJxVURfU0lBSmFOUlRPTVIzblRqQUNwd1ZwYXAyU3lkOEZwc1pFVllTZFJVLWJVZDJybmN1ZHZfcC1XdFZpYWVsQ3BvTWstdURzWGhud2JyWFB6Y3dkVHVobmg0V2kxMmRTcjRUQ3ZMRktSMklCaklwam1VZWt4MFBTazlKUkNXc2R2bjY0dElCZnV6dVZSRkVkSVBidnBZd2pWOUZZc19VQWJvVE85a2E1OWZmNm1zOThHYXVTbE9sYnkwSWE0TlBxTTRKY2ZvSFUiLAogICAgICAgICAicHJvdGVjdGVkIjogImV5Sm1iM0p0WVhSTVpXNW5kR2dpT2pFM05Dd2labTl5YldGMFZHRnBiQ0k2SW1aUklpd2lkR2x0WlNJNklqSXdNVGd0TURVdE1UWlVNREU2TURNNk1qTmFJbjAiCiAgICAgIH0KICAgXQp9"}
dockerfiles/k8s/.bashrc ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ export PS1="[\h \W]$ "
2
+ cat /etc/motd
3
+ echo $BASHPID > /var/run/cwd
dockerfiles/k8s/Dockerfile ADDED
@@ -0,0 +1,44 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ FROM centos:7
2
+
3
+ COPY ./systemctl /usr/bin/systemctl
4
+ COPY ./kubernetes.repo /etc/yum.repos.d/
5
+
6
+
7
+
8
+ RUN yum install -y kubectl-1.27.2 kubeadm-1.27.2 kubelet-1.27.2 \
9
+ #&& mv -f /etc/systemd/system/kubelet.service.d/10-kubeadm.conf /etc/systemd/system/kubelet.service \
10
+ && yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo \
11
+ && yum install -y docker-ce git bash-completion \
12
+ && sed -i -e '4d;5d;8d' /lib/systemd/system/docker.service \
13
+ && yum clean all
14
+
15
+ RUN curl -Lf -o /usr/bin/jq https://github.com/stedolan/jq/releases/download/jq-1.5/jq-linux64 \
16
+ && curl -Lf -o /usr/bin/docker-compose https://github.com/docker/compose/releases/download/1.21.0/docker-compose-$(uname -s)-$(uname -m) \
17
+ && chmod +x /usr/bin/jq /usr/bin/docker-compose
18
+
19
+
20
+ VOLUME ["/var/lib/kubelet"]
21
+
22
+ COPY ./kube* /etc/systemd/system/
23
+ COPY ./wrapkubeadm.sh /usr/local/bin/kubeadm
24
+ COPY ./tokens.csv /etc/pki/tokens.csv
25
+ COPY ./daemon.json /etc/docker/
26
+ COPY ./resolv.conf.override /etc/
27
+ COPY ./docker.service /usr/lib/systemd/system/
28
+ COPY ./.bashrc /root/
29
+
30
+ COPY motd /etc/motd
31
+
32
+
33
+ RUN echo 'source <(kubectl completion bash)' >>~/.bashrc \
34
+ && kubectl completion bash >> /etc/bash_completion.d/kubectl
35
+
36
+ RUN mkdir -p /root/.kube && ln -s /etc/kubernetes/admin.conf /root/.kube/config \
37
+ && rm -f /etc/machine-id
38
+
39
+ WORKDIR /root
40
+
41
+ CMD mount --make-shared / \
42
+ && systemctl start docker \
43
+ && systemctl start kubelet \
44
+ && while true; do script -q -c "/bin/bash -l" /dev/null; done
dockerfiles/k8s/daemon.json ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "experimental": true,
3
+ "debug": true,
4
+ "cri-containerd": true,
5
+ "log-level": "info",
6
+ "tls": false,
7
+ "insecure-registries": [
8
+ "127.0.0.1"
9
+ ],
10
+ "hosts": [
11
+ "unix:///var/run/docker.sock",
12
+ "tcp://0.0.0.0:2375"
13
+ ]
14
+ }
dockerfiles/k8s/docker.service ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ [Unit]
2
+ Description=Docker Application Container Engine
3
+ Documentation=https://docs.docker.com
4
+
5
+ [Service]
6
+ # the default is not to use systemd for cgroups because the delegate issues still
7
+ # exists and systemd currently does not support the cgroup feature set required
8
+ # for containers run by docker
9
+ ExecStart=/usr/bin/dockerd
10
+ ExecReload=/bin/kill -s HUP $MAINPID
11
+ # Having non-zero Limit*s causes performance problems due to accounting overhead
12
+ # in the kernel. We recommend using cgroups to do container-local accounting.
13
+ LimitNOFILE=infinity
14
+ LimitNPROC=infinity
15
+ LimitCORE=infinity
16
+ # Uncomment TasksMax if your systemd version supports it.
17
+ # Only systemd 226 and above support this version.
18
+ #TasksMax=infinity
19
+ TimeoutStartSec=0
20
+ # set delegate yes so that systemd does not reset the cgroups of docker containers
21
+ Delegate=yes
22
+ # kill only the docker process, not all processes in the cgroup
23
+ KillMode=process
24
+ # restart the docker process if it exits prematurely
25
+ Restart=on-failure
26
+ StartLimitBurst=3
27
+ StartLimitInterval=60s
28
+
29
+ [Install]
30
+ WantedBy=multi-user.target
dockerfiles/k8s/kubelet.env ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ KUBELET_KUBECONFIG_ARGS="--bootstrap-kubeconfig=/etc/kubernetes/bootstrap-kubelet.conf --kubeconfig=/etc/kubernetes/kubelet.conf"
2
+ KUBELET_SYSTEM_PODS_ARGS="--pod-manifest-path=/etc/kubernetes/manifests"
3
+ KUBELET_DNS_ARGS="--cluster-dns=10.96.0.10 --cluster-domain=cluster.local"
4
+ KUBELET_AUTHZ_ARGS="--authorization-mode=Webhook --client-ca-file=/etc/kubernetes/pki/ca.crt"
5
+ KUBELET_CGROUP_ARGS="--cgroup-driver=cgroupfs"
6
+ KUBELET_EXTRA_ARGS="--fail-swap-on=false --resolv-conf=/etc/resolv.conf.override --container-runtime-endpoint /run/docker/containerd/containerd.sock "
dockerfiles/k8s/kubelet.service ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ [Service]
2
+ Restart=always
3
+ EnvironmentFile=/etc/systemd/system/kubelet.env
4
+ ExecStart=/usr/bin/kubelet $KUBELET_KUBECONFIG_ARGS $KUBELET_SYSTEM_PODS_ARGS $KUBELET_NETWORK_ARGS $KUBELET_DNS_ARGS $KUBELET_AUTHZ_ARGS $KUBELET_CGROUP_ARGS $KUBELET_EXTRA_ARGS
dockerfiles/k8s/kubernetes.repo ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ [kubernetes]
2
+ name=Kubernetes
3
+ baseurl=https://pkgs.k8s.io/core:/stable:/v1.28/rpm/
4
+ enabled=1
5
+ gpgcheck=1
6
+ gpgkey=https://pkgs.k8s.io/core:/stable:/v1.28/rpm/repodata/repomd.xml.key
7
+ exclude=kubelet kubeadm kubectl cri-tools kubernetes-cni
dockerfiles/k8s/motd ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ WARNING!!!!
3
+
4
+ This is a sandbox environment. Using personal credentials
5
+ is HIGHLY! discouraged. Any consequences of doing so, are
6
+ completely the user's responsibilites.
7
+
8
+ You can bootstrap a cluster as follows:
9
+
10
+ 1. Initializes cluster master node:
11
+
12
+ kubeadm init --apiserver-advertise-address $(hostname -i) --pod-network-cidr 10.5.0.0/16
13
+
14
+
15
+ 2. Initialize cluster networking:
16
+
17
+ kubectl apply -f https://raw.githubusercontent.com/cloudnativelabs/kube-router/master/daemonset/kubeadm-kuberouter.yaml
18
+
19
+
20
+ 3. (Optional) Create an nginx deployment:
21
+
22
+ kubectl apply -f https://raw.githubusercontent.com/kubernetes/website/master/content/en/examples/application/nginx-app.yaml
23
+
24
+
25
+ The PWK team.
26
+
27
+
28
+
dockerfiles/k8s/resolv.conf.override ADDED
@@ -0,0 +1 @@
 
 
1
+ nameserver 8.8.8.8
dockerfiles/k8s/systemctl ADDED
@@ -0,0 +1,281 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/bin/bash
2
+
3
+ function get_unit_file(){
4
+
5
+ local UNIT=$1
6
+
7
+ for DIR in ${UNIT_PATHS[@]} ; do
8
+ if [ -f "${DIR}${UNIT}" ] ; then
9
+ echo "${DIR}${UNIT}"
10
+ break
11
+ fi
12
+ done
13
+
14
+ }
15
+
16
+ function read_option(){
17
+ local OPTION="$1"
18
+ local UNIT_FILE="$2"
19
+ local UNIT_INSTANCE="$3"
20
+
21
+ local UNIT=`basename $UNIT_FILE`
22
+ local UNIT_FULL=`echo $UNIT | sed "s/@/@$UNIT_INSTANCE/"`
23
+
24
+ VALUE="$(grep '^'$OPTION'[= ]' "$UNIT_FILE" | cut -d '=' -f2- | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')"
25
+
26
+ VALUE="`
27
+ echo $VALUE |
28
+ sed -e "s/%[i]/$UNIT_INSTANCE/g" \
29
+ -e "s/%[I]/\"$UNIT_INSTANCE\"/g" \
30
+ -e "s/%[n]/$UNIT_FULL/g" \
31
+ -e "s/%[N]/\"$UNIT_FULL\"/g"
32
+ `"
33
+ # TODO: Add more options from:
34
+ # https://www.freedesktop.org/software/systemd/man/systemd.unit.html#Specifiers
35
+
36
+ echo $VALUE
37
+ }
38
+
39
+ function get_unit_wants() {
40
+
41
+ local UNIT_FILE=$1
42
+ local UNIT=`basename $UNIT_FILE`
43
+
44
+ sort -u <<< `(
45
+ # Print wants from UNIT_PATHS
46
+ for DIR in ${UNIT_PATHS[@]} ; do
47
+ if [ -d "${DIR}${UNIT}.wants" ] ; then
48
+ ls -1 "${DIR}${UNIT}.wants/" | tr '\n' ' '
49
+ fi
50
+ done
51
+
52
+ # Print wants from unit-file
53
+ read_option Wants $UNIT_FILE
54
+ )`
55
+ }
56
+
57
+ function action_start(){
58
+
59
+ # Find depended services
60
+ local UNIT_FILE=$1
61
+ local UNIT_WANTS=(`get_unit_wants $1`)
62
+ local UNIT_INSTANCE=$2
63
+
64
+ # Start depended services
65
+ for UNIT in ${UNIT_WANTS[@]}; do
66
+ exec_action start $UNIT
67
+ done
68
+
69
+ # Load options
70
+ local User=`read_option User $UNIT_FILE $UNIT_INSTANCE`
71
+ local Type=`read_option Type $UNIT_FILE $UNIT_INSTANCE`
72
+ local EnvironmentFile=`read_option EnvironmentFile $UNIT_FILE $UNIT_INSTANCE`
73
+ local ExecStartPre=(`read_option ExecStartPre $UNIT_FILE $UNIT_INSTANCE`)
74
+ local ExecStart=`read_option ExecStart $UNIT_FILE $UNIT_INSTANCE`
75
+ local ExecStartPost=(`read_option ExecStartPost $UNIT_FILE $UNIT_INSTANCE`)
76
+ local Restart=(`read_option Restart $UNIT_FILE $UNIT_INSTANCE`)
77
+ local RestartSec=(`read_option RestartSec $UNIT_FILE $UNIT_INSTANCE`)
78
+ RestartSec=${RestartSec:=5}
79
+
80
+ [ -f "$EnvironmentFile" ] && source "$EnvironmentFile"
81
+
82
+ # Start service
83
+ if [ -z $Type ] || [[ "${Type,,}" == *"simple"* ]] ; then
84
+ if [ "$Restart" == "always" ]; then
85
+ COMMAND='nohup bash -c "while true ; do '"$ExecStart"'; sleep $RestartSec; done" &>/dev/null &'
86
+ else
87
+ COMMAND='nohup '"$ExecStart"' >>/dev/null 2>&1 &'
88
+ fi
89
+ elif [[ "${Type,,}" == *"forking"* ]] || [[ "${Type,,}" == *"oneshot"* ]] ; then
90
+ COMMAND="$ExecStart"
91
+ else
92
+ >&2 echo "Unknown service type $Type"
93
+ fi
94
+
95
+ #[ -z $User ] || COMMAND="su $User -c \"$COMMAND\""
96
+
97
+ while IFS=$'\n' read -a i; do
98
+ eval $i
99
+ done <<< "${ExecStartPre[@]}"
100
+
101
+ eval "$COMMAND"
102
+
103
+ while IFS=$'\n' read -a i; do
104
+ eval $i
105
+ done <<< "${ExecStartPost[@]}"
106
+ }
107
+
108
+ function action_stop(){
109
+
110
+ # Find depended services
111
+ local UNIT_FILE=$1
112
+ local UNIT_WANTS=(`get_unit_wants $1`)
113
+ local UNIT_INSTANCE=$2
114
+
115
+ # Load options
116
+ local User=`read_option User $UNIT_FILE $UNIT_INSTANCE`
117
+ local Type=`read_option Type $UNIT_FILE $UNIT_INSTANCE`
118
+ local EnvironmentFile=`read_option EnvironmentFile $UNIT_FILE $UNIT_INSTANCE`
119
+ local ExecStopPre=(`read_option ExecStartPre $UNIT_FILE $UNIT_INSTANCE`)
120
+ local ExecStop=`read_option ExecStop $UNIT_FILE $UNIT_INSTANCE`
121
+ local ExecStopPost=(`read_option ExecStartPost $UNIT_FILE $UNIT_INSTANCE`)
122
+ local ExecStart=`read_option ExecStart $UNIT_FILE $UNIT_INSTANCE`
123
+
124
+ [ -f "$EnvironmentFile" ] && source "$EnvironmentFile"
125
+
126
+ # Stop service
127
+ if [ -z $ExecStop ] ; then
128
+ COMMAND="kill -TERM \$(pgrep -f \"$ExecStart\")"
129
+ else
130
+ COMMAND="$ExecStop"
131
+ fi
132
+
133
+ #[ -z $User ] || COMMAND="su $User -c \"$COMMAND\""
134
+
135
+ while IFS=$'\n' read -a i; do
136
+ eval $i
137
+ done <<< "${ExecStopPre[@]}"
138
+
139
+ eval "$COMMAND"
140
+
141
+ while IFS=$'\n' read -a i; do
142
+ eval $i
143
+ done <<< "${ExecStopPost[@]}"
144
+ }
145
+
146
+ function action_restart(){
147
+ local UNIT_FILE=$1
148
+ local UNIT_INSTANCE=$2
149
+
150
+ action_stop $UNIT_FILE $UNIT_INSTANCE
151
+ action_start $UNIT_FILE $UNIT_INSTANCE
152
+ }
153
+
154
+
155
+ function action_enable(){
156
+
157
+ local UNIT_FILE=$1
158
+ local UNIT=`basename $UNIT_FILE`
159
+ local UNIT_INSTANCE=$2
160
+ local UNIT_FULL=`echo $UNIT | sed "s/@/@$UNIT_INSTANCE/"`
161
+
162
+ local WantedBy=`read_option WantedBy $UNIT_FILE`
163
+
164
+ if [ -z $WantedBy ] ; then
165
+ >&2 echo "Unit $UNIT have no WantedBy option."
166
+ exit 1
167
+ fi
168
+
169
+ local WANTEDBY_DIR="/etc/systemd/system/$WantedBy.wants"
170
+
171
+ if [ ! -f "$WANTEDBY_DIR/$UNIT_FULL" ] ; then
172
+ mkdir -p $WANTEDBY_DIR
173
+ echo Created symlink from $WANTEDBY_DIR/$UNIT_FULL to $UNIT_FILE.
174
+ ln -s $WANTEDBY_DIR/$UNIT_FULL $UNIT_FILE
175
+ fi
176
+
177
+ }
178
+
179
+ function action_disable(){
180
+
181
+ local UNIT_FILE=$1
182
+ local UNIT=`basename $UNIT_FILE`
183
+ local UNIT_INSTANCE=$2
184
+ local UNIT_FULL=`echo $UNIT | sed "s/@/@$UNIT_INSTANCE/"`
185
+
186
+ local WantedBy=`read_option WantedBy $UNIT_FILE`
187
+
188
+ if [ -z $WantedBy ] ; then
189
+ >&2 echo "Unit $UNIT have no WantedBy option."
190
+ exit 1
191
+ fi
192
+
193
+ local WANTEDBY_DIR="/etc/systemd/system/$WantedBy.wants"
194
+
195
+ if [ -f "$WANTEDBY_DIR/$UNIT_FULL" ] ; then
196
+ echo Removed $WANTEDBY_DIR/$UNIT_FULL.
197
+ rm -f $WANTEDBY_DIR/$UNIT_FULL.
198
+ rmdir --ignore-fail-on-non-empty $WANTEDBY_DIR
199
+ fi
200
+
201
+ }
202
+
203
+ function action_status(){
204
+
205
+ # Find depended services
206
+ local UNIT_FILE=$1
207
+ local UNIT_WANTS=(`get_unit_wants $1`)
208
+ local UNIT_INSTANCE=$2
209
+
210
+ local ExecStart=`read_option ExecStart $UNIT_FILE $UNIT_INSTANCE`
211
+
212
+
213
+ COMMAND="pgrep -f \"$ExecStart\" &>/dev/null"
214
+
215
+
216
+ if eval "$COMMAND"; then
217
+ exit 0
218
+ fi
219
+
220
+ >&2 echo "Loaded: not-found"
221
+ exit 1
222
+ }
223
+
224
+ function action_is_enabled(){
225
+ exit 0
226
+ }
227
+
228
+ function action_is_active(){
229
+ local UNIT=`basename $1`
230
+ if systemctl status $UNIT ; then
231
+ >&2 echo "active"
232
+ exit 0
233
+ fi
234
+
235
+ exit 1
236
+
237
+ }
238
+
239
+ function exec_action(){
240
+
241
+ local ACTION=$1
242
+ local UNIT=$2
243
+
244
+ [[ $UNIT =~ '.' ]] || UNIT="$UNIT.service"
245
+
246
+ if [[ $UNIT =~ '@' ]] ; then
247
+ local UNIT_INSTANCE=`echo $UNIT | cut -d'@' -f2- | cut -d. -f1`
248
+ local UNIT=`echo $UNIT | sed "s/$UNIT_INSTANCE//"`
249
+ fi
250
+
251
+ UNIT_FILE=`get_unit_file $UNIT`
252
+
253
+ if [ -z $UNIT_FILE ] ; then
254
+ >&2 echo "Failed to $ACTION $UNIT: Unit $UNIT not found."
255
+ exit 1
256
+ else
257
+ case "$ACTION" in
258
+ start ) action_start $UNIT_FILE $UNIT_INSTANCE ;;
259
+ stop ) action_stop $UNIT_FILE $UNIT_INSTANCE ;;
260
+ restart ) action_restart $UNIT_FILE $UNIT_INSTANCE ;;
261
+ enable ) action_enable $UNIT_FILE $UNIT_INSTANCE ;;
262
+ disable ) action_disable $UNIT_FILE $UNIT_INSTANCE ;;
263
+ status ) action_status $UNIT_FILE $UNIT_INSTANCE ;;
264
+ is-enabled ) action_is_enabled $UNIT_FILE $UNIT_INSTANCE ;;
265
+ is-active ) action_is_active $UNIT_FILE $UNIT_INSTANCE ;;
266
+ * ) >&2 echo "Unknown operation $ACTION." ; exit 1 ;;
267
+ esac
268
+ fi
269
+ }
270
+
271
+ ACTION="$1"
272
+ UNITS="${@:2}"
273
+ UNIT_PATHS=(
274
+ /etc/systemd/system/
275
+ /usr/lib/systemd/system/
276
+ )
277
+
278
+
279
+ for UNIT in ${UNITS[@]}; do
280
+ exec_action $ACTION $UNIT
281
+ done
dockerfiles/k8s/tokens.csv ADDED
@@ -0,0 +1 @@
 
 
1
+ 31ada4fd-adec-460c-809a-9e56ceb75269,pwd,pwd,"system:admin,system:masters"
dockerfiles/k8s/wrapkubeadm.sh ADDED
@@ -0,0 +1,153 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/bin/bash
2
+ # Copyright 2017 Mirantis
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+
16
+ set -o pipefail
17
+ set -o errtrace
18
+
19
+ apiserver_static_pod="/etc/kubernetes/manifests/kube-apiserver"
20
+
21
+ # jq filters follow.
22
+
23
+ # TODO: think about more secure possibilities
24
+ apiserver_anonymous_auth='.spec.containers[0].command|=map(select(startswith("--token-auth-file")|not))+["--token-auth-file=/etc/pki/tokens.csv"]'
25
+
26
+ # Sets etcd2 as backend
27
+ apiserver_etcd2_backend='.spec.containers[0].command|=map(select(startswith("--storage-backend")|not))+["--storage-backend=etcd2"]'
28
+
29
+ # Make apiserver accept insecure connections on port 8080
30
+ # TODO: don't use insecure port
31
+ #apiserver_insecure_bind_port='.spec.containers[0].command|=map(select(startswith("--insecure-port=")|not))+["--insecure-port=2375"]'
32
+
33
+
34
+ # Update kube-proxy CIDR, enable --masquerade-all and disable conntrack (see dind::frob-proxy below)
35
+ function dind::proxy-cidr-and-no-conntrack {
36
+ cluster_cidr="$(ip addr show docker0 | grep -w inet | awk '{ print $2; }')"
37
+ echo ".items[0].spec.template.spec.containers[0].command |= .+ [\"--cluster-cidr=${cluster_cidr}\", \"--masquerade-all\", \"--conntrack-max-per-core=0\"]"
38
+ }
39
+
40
+
41
+ # Adds route to defualt eth0 interface so 10.96.x.x can go through
42
+ function dind::add-route {
43
+ ip route add 10.96.0.0/16 dev eth0
44
+ }
45
+
46
+
47
+
48
+ function dind::join-filters {
49
+ local IFS="|"
50
+ echo "$*"
51
+ }
52
+
53
+ function dind::frob-apiserver {
54
+ local -a filters=("${apiserver_anonymous_auth}")
55
+
56
+ dind::frob-file "${apiserver_static_pod}" "${filters[@]}"
57
+ }
58
+
59
+ function dind::frob-file {
60
+ local path_base="$1"
61
+ shift
62
+ local filter="$(dind::join-filters "$@")"
63
+ local status=0
64
+ if [[ -f ${path_base}.yaml ]]; then
65
+ dind::yq "${filter}" "${path_base}.yaml" || status=$?
66
+ else
67
+ echo "${path_base}.json or ${path_base}.yaml not found" >&2
68
+ return 1
69
+ fi
70
+ if [[ ${status} -ne 0 ]]; then
71
+ echo "Failed to frob ${path_base}.yaml" >&2
72
+ return 1
73
+ fi
74
+ }
75
+
76
+ function dind::yq {
77
+ local filter="$1"
78
+ local path="$2"
79
+ # We need to use a temp file here because if you feed an object to
80
+ # 'kubectl convert' via stdin, you'll get a List object because
81
+ # multiple input objects are implied
82
+ tmp="$(mktemp tmp-XXXXXXXXXX.json)"
83
+ kubectl convert -f "${path}" --local -o json 2>/dev/null |
84
+ jq "${filter}" > "${tmp}"
85
+ kubectl convert -f "${tmp}" --local -o yaml 2>/dev/null >"${path}"
86
+ rm -f "${tmp}"
87
+ }
88
+
89
+ function dind::frob-proxy {
90
+ # Trying to change conntrack settings fails even in priveleged containers,
91
+ # so we need to avoid it. Here's sample error message from kube-proxy:
92
+ # I1010 21:53:00.525940 1 conntrack.go:57] Setting conntrack hashsize to 49152
93
+ # Error: write /sys/module/nf_conntrack/parameters/hashsize: operation not supported
94
+ # write /sys/module/nf_conntrack/parameters/hashsize: operation not supported
95
+ #
96
+ # Recipe by @errordeveloper:
97
+ # https://github.com/kubernetes/kubernetes/pull/34522#issuecomment-253248985
98
+ local force_apply=--force
99
+ if ! kubectl version --short >&/dev/null; then
100
+ # kubectl 1.4 doesn't have version --short and also it doesn't support apply --force
101
+ force_apply=
102
+ fi
103
+ KUBECONFIG=/etc/kubernetes/admin.conf kubectl -n kube-system get ds -l k8s-app=kube-proxy -o json |
104
+ jq "$(dind::join-filters "$(dind::proxy-cidr-and-no-conntrack)")" | KUBECONFIG=/etc/kubernetes/admin.conf kubectl apply ${force_apply} -f -
105
+
106
+ KUBECONFIG=/etc/kubernetes/admin.conf kubectl -n kube-system delete pods --now -l "k8s-app=kube-proxy"
107
+ }
108
+
109
+
110
+ function dind::wait-for-apiserver {
111
+ echo -n "Waiting for api server to startup"
112
+ local url="https://localhost:6443/api"
113
+ local n=60
114
+ while true; do
115
+ if curl -k -s "${url}" >&/dev/null; then
116
+ break
117
+ fi
118
+ if ((--n == 0)); then
119
+ echo "Error: timed out waiting for apiserver to become available" >&2
120
+ fi
121
+ echo -n "."
122
+ sleep 0.5
123
+ done
124
+ echo ""
125
+ }
126
+
127
+ function dind::frob-cluster {
128
+ #dind::frob-apiserver
129
+ dind::wait-for-apiserver
130
+ dind::frob-proxy
131
+ }
132
+
133
+ # Weave depends on /etc/machine-id being unique
134
+ if [[ ! -f /etc/machine-id ]]; then
135
+ rm -f /etc/machine-id
136
+ systemd-machine-id-setup
137
+ fi
138
+
139
+ if [[ "$@" == "init"* || "$@" == "join"* ]]; then
140
+ # Call kubeadm with params and skip flag
141
+ /usr/bin/kubeadm "$@" --ignore-preflight-errors all --cri-socket /run/docker/containerd/containerd.sock
142
+ else
143
+ # Call kubeadm with params
144
+ /usr/bin/kubeadm "$@"
145
+ fi
146
+
147
+ # Frob cluster
148
+ if [[ "$@" == "init"* && $? -eq 0 && ! "$@" == *"--help"* ]]; then
149
+ dind::frob-cluster
150
+ else
151
+ dind::add-route
152
+ fi
153
+
dockerfiles/pwm/.gitconfig ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ [url "https://"]
2
+ insteadOf = git://