Giter Club home page Giter Club logo

dockerd-ci-proxy's Introduction

NOT MAINTAINED

Use sockguard instead

(As of mid 2018)





dockerd-ci-proxy

Docker Daemon UNIX Socket Proxy for CI Child Containers

Build Status

Summary

Acts as a UNIX socket proxy (eg. for /var/run/docker.sock) for Docker client <-> Docker daemon communication, injecting extra docker run arguments (eg. label/s and cgroup-parent) to all resource creation calls.

Background

Let's say you are running CI (Jenkins, etc) slaves in your Docker-based container scheduled server cluster. And you want to run Docker-in-Docker to allow your CI jobs to spawn containers, but you read @jpetazzo 's post here about instead mounting the host Docker socket into the CI slave container.

At this point, your container scheduler knows about all containers that are started, and takes care of garbage collection and resource allocation for you. You now have another Docker client that can spawn "sibling" containers, with no relationship to what started them. If your CI slave container is terminated, any containers or images left behind by your CI jobs (especially in an Up/Running state) may not be garbage collected. In addition, you may "reserve" CPU/memory resources for containers spawned by your scheduler, but these child containers would not be recognised and allocated resources by the scheduler, causing a non-visible resource oversubscription.

Labels

By putting a UNIX socket proxy between the volume mapping, we can add extra Docker labels to all newly created images or containers, allowing for reaping/GC by existing methods (eg. docker container prune --filter 'labelname=xyz', or alternate approaches for running containers). There is currently no native capability to force adding labels for all operations by a single Docker API client.

The same rule goes for (specific API calls):

  • containers /containers/create
  • images (builds, not pulls) `/build``
  • networks /networks/create
  • volumes /volumes/create
  • services /services/create
  • secrets /secrets/create
  • configs /configs/create

Another approach to this is for the native Docker client to support default labels in the client config files. Requested upstream here - this will only cover using the official Docker CLI client and not alternate clients that talk to the same UNIX socket, which this project would cover.

Note: docker import operations will not apply a label currently. This feature could be added if worthwhile for completeness (the API seems to have what's required).

Parent CGroup

You can also apply a custom cgroup-parent to all child containers so they are grouped, to avoid OOM collateral damage to your other workloads on your container scheduler managed cluster, and "reserve" system resources via your scheduler. Eg. you may need 256MB for a Jenkins agent, but you might allocate 2048MB and the child containers will use the surplus when spawned within the same parent cgroup.

This will be applied for /containers/create API calls only (docker run effectively), when the --cgroup-parent (-cg) flag is set.

There is currently no way to define the CGroup name to be used, it is detected automatically. As this process is designed to be run with access to the Docker daemon socket, a /containers/${id-self}/json API call is performed and the CgroupParent value is used (shared parent for this container + any children). If CgroupParent is empty and --cgroup-parent is enabled, the /containers/create API call will fail with an error.

Parent CGroup Container Startup Example

Concept seems to work:

cd /sys/fs/cgroup/memory
mkdir testcontainergroup
cd testcontainergroup
echo 134217728 > memory.limit_in_bytes
docker run -it --rm --test-cgroup=/testcontainergroup/ alpine:3.6 sh
(run something that consumes memory, and it should max out about 128MB)

Note: docker stats will still show the unconstrained memory threshold, not the parent cgroup limit.

Usage

NAME:
   dockerd-ci-proxy - Docker Daemon UNIX Socket Proxy for CI Child Containers

USAGE:
   dockerd-ci-proxy [global options] command [command options] [arguments...]

VERSION:
   0.0.1

COMMANDS:
     help, h  Shows a list of commands or help for one command

GLOBAL OPTIONS:
   --debug, -d                       Debug Mode [$DCP_DEBUG]
   --dockersocket value, --ds value  The Docker daemon API UNIX socket to connect to (default: "/var/run/docker.sock") [$DCP_DOCKER_SOCKET]
   --listensocket value, --ls value  The UNIX listen socket for this process, Docker API clients will point at this path (default: "/var/run/docker-ci-proxy.sock") [$DCP_LISTEN_SOCKET]
   --cgroupparent, --cp              If enabled, overrides the CgroupParent of create operations to match this container [$DCP_CGROUP_PARENT]
   --labelname value, --ln value     The Docker label name to apply to resources (default: "Created-Via") [$DCP_LABEL_NAME]
   --labelvalue value, --lv value    The Docker label value to apply to resources (default: "dockerd-ci-proxy") [$DCP_LABEL_VALUE]
   --help, -h                        show help
   --version, -v                     print the version

Credits

After I almost completed this project, I was hitting issues with /attach API calls failing to "upgrade" (using HTTP/1.1 101 UPGRADED responses). I then found https://github.com/buildkite/sockguard which looks to attempt to solve at least half of the goals of this project (label resources), but also attempts to perform resources restriction, very cool.

License

Licensed under the MIT License

dockerd-ci-proxy's People

Contributors

cpuid avatar

Stargazers

 avatar

Watchers

 avatar  avatar

dockerd-ci-proxy's Issues

Docker API /wait?condition=next calls hang / do not return

When a docker run call is fired off, it triggers a /containers/create API call, then a wait for container /wait API call.

dcp_1       | 2018/07/22 16:44:21 dockerd-ci-proxy -=- MITM -- New request received:
dcp_1       | 2018/07/22 16:44:21 dockerd-ci-proxy -=- MITM -- GET /_ping
dcp_1       | 2018/07/22 16:44:21 dockerd-ci-proxy -=- MITM -- Headers: map[User-Agent:[Docker-Client/18.03.1-ce (linux)]]
dcp_1       | 2018/07/22 16:44:21 dockerd-ci-proxy -=- ----------
dcp_1       | 2018/07/22 16:44:21 dockerd-ci-proxy -=- MITM -- Response sent to client.
dcp_1       | 2018/07/22 16:44:21 dockerd-ci-proxy -=- ==========
dcp_1       | 2018/07/22 16:44:21 dockerd-ci-proxy -=- MITM -- New request received:
dcp_1       | 2018/07/22 16:44:21 dockerd-ci-proxy -=- MITM -- POST /v1.31/containers/create
dcp_1       | 2018/07/22 16:44:21 dockerd-ci-proxy -=- MITM -- Headers: map[Content-Type:[application/json] User-Agent:[Docker-Client/18.03.1-ce (linux)] Content-Length:[1440]]
dcp_1       | 2018/07/22 16:44:21 dockerd-ci-proxy -=- ----------
dcp_1       | 2018/07/22 16:44:21 dockerd-ci-proxy -=- MITM -- Method/URI match, parsing out request body.
dcp_1       | 2018/07/22 16:44:21 dockerd-ci-proxy -=- MITM -- Body: {"Hostname":"","Domainname":"","User":"","AttachStdin":false,"AttachStdout":false,"AttachStderr":false,"Tty":false,"OpenStdin":false,"StdinOnce":false,"Env":[],"Cmd":["sleep","5"],"Image":"alpine:3.8","Volumes":{},"WorkingDir":"","Entrypoint":null,"OnBuild":null,"Labels":{},"HostConfig":{"Binds":null,"ContainerIDFile":"","LogConfig":{"Type":"","Config":{}},"NetworkMode":"default","PortBindings":{},"RestartPolicy":{"Name":"no","MaximumRetryCount":0},"AutoRemove":false,"VolumeDriver":"","VolumesFrom":null,"CapAdd":null,"CapDrop":null,"Dns":[],"DnsOptions":[],"DnsSearch":[],"ExtraHosts":null,"GroupAdd":null,"IpcMode":"","Cgroup":"","Links":null,"OomScoreAdj":0,"PidMode":"","Privileged":false,"PublishAllPorts":false,"ReadonlyRootfs":false,"SecurityOpt":null,"UTSMode":"","UsernsMode":"","ShmSize":0,"ConsoleSize":[0,0],"Isolation":"","CpuShares":0,"Memory":0,"NanoCpus":0,"CgroupParent":"","BlkioWeight":0,"BlkioWeightDevice":[],"BlkioDeviceReadBps":null,"BlkioDeviceWriteBps":null,"BlkioDeviceReadIOps":null,"BlkioDeviceWriteIOps":null,"CpuPeriod":0,"CpuQuota":0,"CpuRealtimePeriod":0,"CpuRealtimeRuntime":0,"CpusetCpus":"","CpusetMems":"","Devices":[],"DeviceCgroupRules":null,"DiskQuota":0,"KernelMemory":0,"MemoryReservation":0,"MemorySwap":0,"MemorySwappiness":-1,"OomKillDisable":false,"PidsLimit":0,"Ulimits":null,"CpuCount":0,"CpuPercent":0,"IOMaximumIOps":0,"IOMaximumBandwidth":0},"NetworkingConfig":{"EndpointsConfig":{}}}
dcp_1       | 
dcp_1       | 2018/07/22 16:44:21 dockerd-ci-proxy -=- ----------
dcp_1       | 2018/07/22 16:44:21 dockerd-ci-proxy -=- MITM -- Response sent to client.

And the second API call:

dcp_1       | 2018/07/22 16:44:21 dockerd-ci-proxy -=- ==========
dcp_1       | 2018/07/22 16:44:21 dockerd-ci-proxy -=- MITM -- New request received:
dcp_1       | 2018/07/22 16:44:21 dockerd-ci-proxy -=- MITM -- POST /v1.31/containers/830e63a8fa90258088aef32f161d652cb561c50bb094dfab1f8b5d59ae9f3bf9/wait?condition=next-exit
dcp_1       | 2018/07/22 16:44:21 dockerd-ci-proxy -=- MITM -- Headers: map[Content-Length:[0] Content-Type:[text/plain] User-Agent:[Docker-Client/18.03.1-ce (linux)]]
dcp_1       | 2018/07/22 16:44:21 dockerd-ci-proxy -=- ----------

The second call hangs indefinitely, and the Docker CLI will hang also. This is regardless of if the container is started with -d (background) or -it (interactive).

Another interesting sidenote: the container sits in a Created state but does not actually get started. It's very possible this is due to the wait step not returning?

$ docker ps -a
CONTAINER ID        IMAGE                     COMMAND             CREATED             STATUS              PORTS               NAMES
830e63a8fa90        alpine:3.8                "sleep 5"           4 minutes ago       Created                                 upbeat_gates
  • debug/test how this looks using socat outside of the proxy
  • fix the proxy implementation

Wire things up

Get the MVP working:

  • wire up the socket proxy to the CLI args/inputs etc
  • start intercepting and modifying the right POST calls to the Docker daemon
    • POST /containers/create
    • POST /build
    • POST /images/create
    • POST /networks/create
    • POST /volumes/create
    • POST /services/create

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.