Skip to content

Commit fa90a46

Browse files
add --gpu to allow the use of GPUs
1 parent c727afd commit fa90a46

File tree

345 files changed

+156909
-12
lines changed

Some content is hidden

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

345 files changed

+156909
-12
lines changed

Dockerfile

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
ARG DOCKER_REG=docker.io
2+
FROM ${DOCKER_REG}/qnib/alplain-golang AS build
3+
4+
WORKDIR /usr/local/src/github.com/qnib/doxy
5+
COPY main.go ./main.go
6+
COPY proxy ./proxy
7+
COPY vendor/ vendor/
8+
RUN govendor install
9+
10+
## Build final image
11+
FROM alpine:3.5
12+
13+
COPY --from=build /usr/local/bin/doxy /usr/local/bin/
14+
CMD ["/usr/local/bin/doxy"]

GPU.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# GPU Support
2+
3+
As a Proof-of-Concept how to implement GPU (and InfiniBand) support, `doxy` was extended to allow for injection of payload to the `docker create` call.
4+
5+
On an `p2.xlarge` instance with CUDA support, `doxy:gpu` was started like that.
6+
7+
```bash
8+
$ docker run -v /var/run:/var/run/ -ti --rm qnib/doxy:gpu doxy --pattern-key=hpc --debug --proxy-socket=/var/run/hpc.sock --gpu
9+
```
10+
11+
The pattern `hpc` allows for read/write endpoints to be used and `--gpu` injects bind-mounts, device-mappings and environment variables to make it work.
12+
13+
```bash
14+
root@ip-172-31-28-27:~# docker -H unix:///var/run/hpc.sock create nvidia/cuda nvidia-smi -L
15+
6b708d7cda36b9c37e325893108839f3b02f172e40ab97182fa77d770cc219fb
16+
root@ip-172-31-28-27:~# docker start -a 6b708d7cda36b9c37e325893108839f3b02f172e40ab97182fa77d770cc219fb
17+
GPU 0: Tesla K80 (UUID: GPU-234d5537-ea27-68cd-7337-ee21b2f34bf1)
18+
root@ip-172-31-28-27:~#
19+
```
20+
21+
When `start`ing the container the default socket is used; as I had issue to pass `stdin`/`stdout` through.
22+
The command hangs with the `doxy`-socket.
23+
I suspect issues with `stdin`/`stdout` passthrough when proxying the two unix-sockets. :/

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ GLOBAL OPTIONS:
1616
$ ./doxy_darwin
1717
2017/08/18 11:37:43 [II] Start Version: 0.1.0
1818
2017/08/18 11:37:43 Error reading patterns file (open /etc/doxy.pattern: no such file or directory), using default patterns
19-
2017/08/18 11:37:43 [gk-soxy] Listening on /tmp/doxy.sock
19+
2017/08/18 11:37:43 [doxy] Listening on /tmp/doxy.sock
2020
```
2121
2222
## Filter mechanism
@@ -79,7 +79,7 @@ $ ./doxy_darwin -debug
7979
2017/08/18 11:44:50 4 : ^/(v\d\.\d+/)?nodes(/\w+)?$
8080
2017/08/18 11:44:50 5 : ^/(v\d\.\d+/)?info$
8181
2017/08/18 11:44:50 6 : ^/_ping$
82-
2017/08/18 11:44:50 [gk-soxy] Listening on /tmp/doxy.sock
82+
2017/08/18 11:44:50 [doxy] Listening on /tmp/doxy.sock
8383
[negroni] 2017-08-18T11:45:00+02:00 | 200 | 3.800713ms | docker | GET /_ping
8484
[negroni] 2017-08-18T11:45:00+02:00 | 403 | 34.067µs | docker | GET /v1.31/containers/a62250e0890a/export
8585
[negroni] 2017-08-18T11:45:04+02:00 | 200 | 1.800044ms | docker | GET /_ping

main.go

Lines changed: 50 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"github.com/zpatrick/go-config"
77
"github.com/codegangsta/cli"
88
"github.com/qnib/doxy/proxy"
9+
"strings"
910
)
1011

1112
var (
@@ -21,11 +22,37 @@ var (
2122
Usage: "Proxy socket to be created",
2223
EnvVar: "DOXY_PROXY_SOCKET",
2324
}
25+
proxyPatternKey = cli.StringFlag{
26+
Name: "pattern-key",
27+
Value: "default",
28+
Usage: "pattern key predefined",
29+
EnvVar: "DOXY_PATTERN_KEY",
30+
}
31+
gpuEnabled = cli.BoolFlag{
32+
Name: "gpu",
33+
Usage: "Map devices, bind-mounts and environment into each container to allow GPU usage",
34+
EnvVar: "DOXY_GPU_ENABLED",
35+
}
36+
constrainUser = cli.BoolFlag{
37+
Name: "user-pinning",
38+
Usage: "Pin user within container to the UID calling the command",
39+
EnvVar: "DOXY_USER_PINNING_ENABLED",
40+
}
2441
debugFlag = cli.BoolFlag{
2542
Name: "debug",
2643
Usage: "Print proxy requests",
2744
EnvVar: "DOXY_DEBUG",
2845
}
46+
bindAddFlag = cli.StringFlag{
47+
Name: "add-binds",
48+
Usage: "Comma separated list of bind-mounts to add",
49+
EnvVar: "DOXY_ADDITIONAL_BINDS",
50+
}
51+
devMapFlag = cli.StringFlag{
52+
Name: "device-mappings",
53+
Usage: "Comma separated list of device mappings",
54+
EnvVar: "DOXY_DEVICE_MAPPINGS",
55+
}
2956
patternFileFlag = cli.StringFlag{
3057
Name: "pattern-file",
3158
Value: proxy.PATTERN_FILE,
@@ -41,6 +68,10 @@ func EvalOptions(cfg *config.Config) (po []proxy.ProxyOption) {
4168
po = append(po, proxy.WithDockerSocket(dockerSock))
4269
debug, _ := cfg.Bool("debug")
4370
po = append(po, proxy.WithDebugValue(debug))
71+
devMaps, _ := cfg.String("device-mappings")
72+
gpu, _ := cfg.Bool("gpu")
73+
po = append(po, proxy.WithGpuValue(gpu))
74+
po = append(po, proxy.WithDevMappings(strings.Split(devMaps,",")))
4475
return
4576
}
4677

@@ -50,18 +81,32 @@ func EvalPatternOpts(cfg *config.Config) (proxy.ProxyOption) {
5081
defer reader.Close()
5182
patterns := []string{}
5283
if err != nil {
53-
log.Printf("Error reading patterns file (%s), using default patterns\n", err.Error())
54-
return proxy.WithPatterns(proxy.DEFAULT_PATTERNS)
84+
patternsKey, _ := cfg.String("pattern-key")
85+
if patterns, ok := proxy.PATTERNS[patternsKey]; ok {
86+
log.Printf("Error reading patterns file '%s', using %s patterns\n", err.Error(), patternsKey)
87+
return proxy.WithPatterns(patterns)
88+
}
89+
log.Printf("Could not find pattern-key '%s'\n", patternsKey)
90+
os.Exit(1)
91+
5592
}
5693
patterns, err = proxy.ReadPatterns(reader)
5794
return proxy.WithPatterns(patterns)
5895
}
5996

97+
func EvalBindMountOpts(cfg *config.Config) (proxy.ProxyOption) {
98+
bindStr, _ := cfg.String("add-binds")
99+
bindMounts := strings.Split(bindStr,",")
100+
return proxy.WithBindMounts(bindMounts)
101+
}
102+
103+
60104
func RunApp(ctx *cli.Context) {
61105
log.Printf("[II] Start Version: %s", ctx.App.Version)
62106
cfg := config.NewConfig([]config.Provider{config.NewCLI(ctx, true)})
63107
po := EvalOptions(cfg)
64108
po = append(po, EvalPatternOpts(cfg))
109+
po = append(po, EvalBindMountOpts(cfg))
65110
p := proxy.NewProxy(po...)
66111
p.Run()
67112
}
@@ -75,7 +120,10 @@ func main() {
75120
dockerSocketFlag,
76121
proxySocketFlag,
77122
debugFlag,
123+
gpuEnabled,
78124
patternFileFlag,
125+
proxyPatternKey,
126+
bindAddFlag,
79127
}
80128
app.Action = RunApp
81129
app.Run(os.Args)

proxy/helper.go

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
package proxy
2+
3+
import (
4+
"github.com/docker/docker/api/types/container"
5+
"github.com/docker/docker/api/types/network"
6+
"io"
7+
"bytes"
8+
"encoding/json"
9+
"net/http"
10+
"strings"
11+
"fmt"
12+
)
13+
14+
type Headers map[string][]string
15+
16+
17+
18+
type configWrapper struct {
19+
*container.Config
20+
HostConfig *container.HostConfig
21+
NetworkingConfig *network.NetworkingConfig
22+
}
23+
24+
func createDevMapping(dev string) (dm container.DeviceMapping, err error) {
25+
spl := strings.Split(dev, ":")
26+
switch len(spl) {
27+
case 2:
28+
dm = container.DeviceMapping{
29+
PathOnHost: spl[0],
30+
PathInContainer: spl[1],
31+
}
32+
case 3:
33+
dm = container.DeviceMapping{
34+
PathOnHost: spl[0],
35+
PathInContainer: spl[1],
36+
CgroupPermissions: spl[2],
37+
}
38+
default:
39+
return dm, fmt.Errorf("string needs to specify <src>:<dst>[:permission]")
40+
}
41+
return
42+
}
43+
44+
func encodeBody(obj interface{}, header http.Header) (io.Reader, http.Header, error) {
45+
if obj == nil {
46+
return nil, header, nil
47+
}
48+
49+
body, err := encodeData(obj)
50+
if err != nil {
51+
return nil, header, err
52+
}
53+
return body, header, nil
54+
}
55+
56+
func encodeData(data interface{}) (*bytes.Buffer, error) {
57+
params := bytes.NewBuffer(nil)
58+
if data != nil {
59+
if err := json.NewEncoder(params).Encode(data); err != nil {
60+
return nil, err
61+
}
62+
}
63+
return params, nil
64+
}

proxy/main.go

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ const (
1616
)
1717

1818
var (
19-
DEFAULT_PATTERNS = []string{
19+
DEF_PAT = []string{
2020
`^/(v\d\.\d+/)?containers(/\w+)?/(json|stats|top)$`,
2121
`^/(v\d\.\d+/)?services(/[0-9a-f]+)?$`,
2222
`^/(v\d\.\d+/)?tasks(/\w+)?$`,
@@ -27,12 +27,28 @@ var (
2727
`^/(v\d\.\d+/)?version$`,
2828
"^/_ping$",
2929
}
30+
HPC_PAT = []string{
31+
`^/(v\d\.\d+/)?containers(/\w+)?/(json|stats|top|create|start|run|kill)$`,
32+
`^/(v\d\.\d+/)?services(/[0-9a-f]+)?$`,
33+
`^/(v\d\.\d+/)?tasks(/\w+)?$`,
34+
`^/(v\d\.\d+/)?networks(/\w+)?$`,
35+
`^/(v\d\.\d+/)?volumes(/\w+)?$`,
36+
`^/(v\d\.\d+/)?nodes(/\w+)?$`,
37+
`^/(v\d\.\d+/)?info$`,
38+
`^/(v\d\.\d+/)?version$`,
39+
"^/_ping$",
40+
}
41+
PATTERNS = map[string][]string{
42+
"default": DEF_PAT,
43+
"hpc": HPC_PAT,
44+
}
3045
)
3146

3247
type Proxy struct {
3348
dockerSocket, newSocket string
34-
debug bool
49+
debug, gpu bool
3550
patterns []string
51+
bindMounts,devMappings []string
3652
}
3753

3854
func NewProxy(opts ...ProxyOption) Proxy {
@@ -44,7 +60,10 @@ func NewProxy(opts ...ProxyOption) Proxy {
4460
dockerSocket: options.DockerSocket,
4561
newSocket: options.ProxySocket,
4662
debug: options.Debug,
63+
gpu: options.Gpu,
4764
patterns: options.Patterns,
65+
bindMounts: options.BindMounts,
66+
devMappings: options.DevMappings,
4867
}
4968
}
5069

@@ -59,7 +78,7 @@ func (p *Proxy) GetOptions() map[string]interface{} {
5978
}
6079

6180
func (p *Proxy) Run() {
62-
upstream := NewUpstream(p.dockerSocket, p.patterns)
81+
upstream := NewUpstream(p.dockerSocket, p.patterns, p.bindMounts, p.devMappings, p.gpu)
6382
sigc := make(chan os.Signal, 1)
6483
signal.Notify(sigc, os.Interrupt, os.Kill, syscall.SIGTERM)
6584
l, err := ListenToNewSock(p.newSocket, sigc)

proxy/options.go

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,20 @@ package proxy
33
type ProxyOptions struct {
44
DockerSocket string
55
ProxySocket string
6-
Debug bool
6+
Debug,Gpu bool
77
Patterns []string
8+
BindMounts []string
9+
DevMappings []string
810
}
911

1012
var defaultProxyOptions = ProxyOptions{
1113
DockerSocket: DOCKER_SOCKET,
1214
ProxySocket: PROXY_SOCKET,
1315
Debug: false,
16+
Gpu: false,
1417
Patterns: []string{},
18+
BindMounts: []string{},
19+
DevMappings: []string{},
1520
}
1621

1722
type ProxyOption func(*ProxyOptions)
@@ -40,6 +45,12 @@ func WithDebugEnabled() ProxyOption {
4045
}
4146
}
4247

48+
func WithGpuValue(b bool) ProxyOption {
49+
return func(o *ProxyOptions) {
50+
o.Gpu = b
51+
}
52+
}
53+
4354
func WithPattern(p string) ProxyOption {
4455
return func(o *ProxyOptions) {
4556
o.Patterns = append(o.Patterns, p)
@@ -52,3 +63,14 @@ func WithPatterns(p []string) ProxyOption {
5263
}
5364
}
5465

66+
func WithBindMounts(bm []string) ProxyOption {
67+
return func(o *ProxyOptions) {
68+
o.BindMounts = bm
69+
}
70+
}
71+
72+
func WithDevMappings(dm []string) ProxyOption {
73+
return func(o *ProxyOptions) {
74+
o.DevMappings = dm
75+
}
76+
}

0 commit comments

Comments
 (0)