Apache Mesos
docker.hpp
Go to the documentation of this file.
1 // Licensed to the Apache Software Foundation (ASF) under one
2 // or more contributor license agreements. See the NOTICE file
3 // distributed with this work for additional information
4 // regarding copyright ownership. The ASF licenses this file
5 // to you under the Apache License, Version 2.0 (the
6 // "License"); you may not use this file except in compliance
7 // with the License. You may obtain a copy of the License at
8 //
9 // http://www.apache.org/licenses/LICENSE-2.0
10 //
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
16 
17 #ifndef __DOCKER_HPP__
18 #define __DOCKER_HPP__
19 
20 #include <map>
21 #include <mutex>
22 #include <string>
23 #include <utility>
24 #include <vector>
25 
26 #include <process/future.hpp>
27 #include <process/owned.hpp>
28 #include <process/subprocess.hpp>
29 
30 #include <stout/duration.hpp>
31 #include <stout/json.hpp>
32 #include <stout/none.hpp>
33 #include <stout/nothing.hpp>
34 #include <stout/option.hpp>
35 #include <stout/path.hpp>
36 #include <stout/version.hpp>
37 
38 #include <stout/os/rm.hpp>
39 
40 #include "mesos/resources.hpp"
41 
42 #include "messages/flags.hpp"
43 
44 // OS-specific default prefix to be used for the DOCKER_HOST environment
45 // variable. Note that on Linux, the default prefix is the only prefix
46 // available; only Windows supports multiple prefixes.
47 // TODO(hausdorff): Add support for the Windows `tcp://` prefix as well.
48 #ifdef __WINDOWS__
49 constexpr char DEFAULT_DOCKER_HOST_PREFIX[] = "npipe://";
50 #else
51 constexpr char DEFAULT_DOCKER_HOST_PREFIX[] = "unix://";
52 #endif // __WINDOWS__
53 
54 // Abstraction for working with Docker (modeled on CLI).
55 //
56 // TODO(benh): Make futures returned by functions be discardable.
57 class Docker
58 {
59 public:
60  // Create Docker abstraction and optionally validate docker.
62  const std::string& path,
63  const std::string& socket,
64  bool validate = true,
65  const Option<JSON::Object>& config = None());
66 
67  virtual ~Docker() {}
68 
69  struct Device
70  {
73 
74  struct Access
75  {
76  Access() : read(false), write(false), mknod(false) {}
77 
78  bool read;
79  bool write;
80  bool mknod;
81  } access;
82  };
83 
84  struct PortMapping
85  {
86  uint32_t hostPort;
87  uint32_t containerPort;
89  };
90 
91  class Container
92  {
93  public:
94  static Try<Container> create(
95  const std::string& output);
96 
97  // Returns the docker inspect output.
98  const std::string output;
99 
100  // Returns the ID of the container.
101  const std::string id;
102 
103  // Returns the name of the container.
104  const std::string name;
105 
106  // Returns the pid of the container, or None if the container is
107  // not running.
109 
110  // Returns if the container has already started. This field is
111  // needed since pid is empty when the container terminates.
112  const bool started;
113 
114  // Returns the IPv4 address of the container, or `None()` if no
115  // IPv4 address has been assigned.
117 
118  // Returns the IPv6 address of the container, or `None()` if no
119  // IPv6 address has been assigned.
121 
122  const std::vector<Device> devices;
123 
124  // Returns the DNS nameservers set by "--dns" option.
125  const std::vector<std::string> dns;
126 
127  // Returns the DNS options set by "--dns-option" option.
128  const std::vector<std::string> dnsOptions;
129 
130  // Returns the DNS search domains set by "--dns-search" option.
131  const std::vector<std::string> dnsSearch;
132 
133  private:
134  Container(
135  const std::string& _output,
136  const std::string& _id,
137  const std::string& _name,
138  const Option<pid_t>& _pid,
139  bool _started,
140  const Option<std::string>& _ipAddress,
141  const Option<std::string>& _ip6Address,
142  const std::vector<Device>& _devices,
143  const std::vector<std::string>& _dns,
144  const std::vector<std::string>& _dnsOptions,
145  const std::vector<std::string>& _dnsSearch)
146  : output(_output),
147  id(_id),
148  name(_name),
149  pid(_pid),
150  started(_started),
151  ipAddress(_ipAddress),
152  ip6Address(_ip6Address),
153  devices(_devices),
154  dns(_dns),
155  dnsOptions(_dnsOptions),
156  dnsSearch(_dnsSearch) {}
157  };
158 
159  class Image
160  {
161  public:
162  static Try<Image> create(const JSON::Object& json);
163 
165 
167 
168  private:
169  Image(const Option<std::vector<std::string>>& _entrypoint,
170  const Option<std::map<std::string, std::string>>& _environment)
171  : entrypoint(_entrypoint),
172  environment(_environment) {}
173  };
174 
175  // See https://docs.docker.com/engine/reference/run for a complete
176  // explanation of each option.
178  {
179  public:
180  static Try<RunOptions> create(
181  const mesos::ContainerInfo& containerInfo,
182  const mesos::CommandInfo& commandInfo,
183  const std::string& containerName,
184  const std::string& sandboxDirectory,
185  const std::string& mappedDirectory,
186  const Option<mesos::Resources>& resourceRequests = None(),
187  bool enableCfsQuota = false,
188  const Option<std::map<std::string, std::string>>& env = None(),
189  const Option<std::vector<Device>>& devices = None(),
191  defaultContainerDNS = None(),
192  const Option<google::protobuf::Map<std::string, mesos::Value::Scalar>>&
193  resourceLimits = None());
194 
195  // "--privileged" option.
197 
198  // "--cpu-shares" option.
200 
201  // "--cpu-quota" option.
203 
204  // "--memory-reservation" options.
206 
207  // "--memory" option.
209 
210  // "--oom-score-adj" option.
212 
213  // Environment variable overrides. These overrides will be passed
214  // to docker container through "--env-file" option.
215  std::map<std::string, std::string> env;
216 
217  // "--volume" option.
218  std::vector<std::string> volumes;
219 
220  // "--volume-driver" option.
222 
223  // "--network" option.
225 
226  // "--hostname" option.
228 
229  // "--dns" option.
230  std::vector<std::string> dns;
231 
232  // "--dns-search" option.
233  std::vector<std::string> dnsSearch;
234 
235  // "--dns-opt" option.
236  std::vector<std::string> dnsOpt;
237 
238  // Port mappings for "-p" option.
239  std::vector<PortMapping> portMappings;
240 
241  // "--device" option.
242  std::vector<Device> devices;
243 
244  // "--entrypoint" option.
246 
247  // "--name" option.
249 
250  // Additional docker options passed through containerizer.
251  std::vector<std::string> additionalOptions;
252 
253  // "IMAGE[:TAG|@DIGEST]" part of docker run.
254  std::string image;
255 
256  // Arguments for docker run.
257  std::vector<std::string> arguments;
258  };
259 
260  // Performs 'docker run IMAGE'. Returns the exit status of the
261  // container. Note that currently the exit status may correspond
262  // to the exit code from a failure of the docker client or daemon
263  // rather than the container. Docker >= 1.10 [1] uses the following
264  // exit statuses inherited from 'chroot':
265  // 125 if the error is with Docker daemon itself.
266  // 126 if the contained command cannot be invoked.
267  // 127 if the contained command cannot be found.
268  // Exit code of contained command otherwise.
269  //
270  // [1]: https://github.com/docker/docker/pull/14012
272  const RunOptions& options,
273  const process::Subprocess::IO& _stdout =
275  const process::Subprocess::IO& _stderr =
277 
278  // Returns the current docker version.
279  virtual process::Future<Version> version() const;
280 
281  // Performs 'docker stop -t TIMEOUT CONTAINER'. If remove is true then a rm -f
282  // will be called when stop failed, otherwise a failure is returned. The
283  // timeout parameter will be passed through to docker and is the amount of
284  // time for docker to wait after stopping a container before killing it.
285  // A value of zero (the default value) is the same as issuing a
286  // 'docker kill CONTAINER'.
288  const std::string& containerName,
289  const Duration& timeout = Seconds(0),
290  bool remove = false) const;
291 
292  // Performs 'docker kill --signal=<signal> CONTAINER'.
294  const std::string& containerName,
295  int signal) const;
296 
297  // Performs 'docker rm (-f) CONTAINER'.
299  const std::string& containerName,
300  bool force = false) const;
301 
302  // Performs 'docker inspect CONTAINER'. If retryInterval is set,
303  // we will keep retrying inspect until the container is started or
304  // the future is discarded.
306  const std::string& containerName,
307  const Option<Duration>& retryInterval = None()) const;
308 
309  // Performs 'docker ps (-a)'.
311  bool all = false,
312  const Option<std::string>& prefix = None()) const;
313 
315  const std::string& directory,
316  const std::string& image,
317  bool force = false) const;
318 
319  // Validate current docker version is not less than minVersion.
320  virtual Try<Nothing> validateVersion(const Version& minVersion) const;
321 
322  virtual std::string getPath()
323  {
324  return path;
325  }
326 
327  virtual std::string getSocket()
328  {
329  return socket;
330  }
331 
332 protected:
333  // Uses the specified path to the Docker CLI tool.
334  Docker(const std::string& _path,
335  const std::string& _socket,
336  const Option<JSON::Object>& _config)
337  : path(_path),
338  socket(DEFAULT_DOCKER_HOST_PREFIX + _socket),
339  config(_config) {}
340 
341 private:
342  static process::Future<Version> _version(
343  const std::string& cmd,
344  const process::Subprocess& s);
345 
346  static process::Future<Version> __version(
347  const process::Future<std::string>& output);
348 
349  static process::Future<Nothing> _stop(
350  const Docker& docker,
351  const std::string& containerName,
352  const std::string& cmd,
353  const process::Subprocess& s,
354  bool remove);
355 
356  static void _inspect(
357  const std::vector<std::string>& argv,
359  const Option<Duration>& retryInterval,
360  std::shared_ptr<std::pair<lambda::function<void()>, std::mutex>>
361  callback);
362 
363  static void __inspect(
364  const std::vector<std::string>& argv,
366  const Option<Duration>& retryInterval,
368  const process::Subprocess& s,
369  std::shared_ptr<std::pair<lambda::function<void()>, std::mutex>>
370  callback);
371 
372  static void ___inspect(
373  const std::vector<std::string>& argv,
375  const Option<Duration>& retryInterval,
376  const process::Future<std::string>& output,
377  std::shared_ptr<std::pair<lambda::function<void()>, std::mutex>>
378  callback);
379 
381  const Docker& docker,
382  const std::string& cmd,
383  const process::Subprocess& s,
386 
388  const Docker& docker,
389  const Option<std::string>& prefix,
390  const std::string& output);
391 
392  static void inspectBatches(
393  process::Owned<std::vector<Docker::Container>> containers,
394  process::Owned<std::vector<std::string>> lines,
395  process::Owned<process::Promise<std::vector<Docker::Container>>> promise,
396  const Docker& docker,
397  const Option<std::string>& prefix);
398 
399  static std::vector<process::Future<Docker::Container>> createInspectBatch(
400  process::Owned<std::vector<std::string>> lines,
401  const Docker& docker,
402  const Option<std::string>& prefix);
403 
404  static process::Future<Image> _pull(
405  const Docker& docker,
406  const process::Subprocess& s,
407  const std::string& directory,
408  const std::string& image,
409  const std::string& path,
410  const std::string& socket,
411  const Option<JSON::Object>& config,
413 
414  static process::Future<Image> __pull(
415  const Docker& docker,
416  const std::string& directory,
417  const std::string& image,
418  const std::string& path,
419  const std::string& socket,
420  const Option<JSON::Object>& config);
421 
422  static process::Future<Image> ___pull(
423  const Docker& docker,
424  const process::Subprocess& s,
425  const std::string& cmd,
426  const std::string& directory,
427  const std::string& image);
428 
429  static process::Future<Image> ____pull(
430  const std::string& output);
431 
432  static void pullDiscarded(
433  const process::Subprocess& s,
434  const std::string& cmd);
435 
436  const std::string path;
437  const std::string socket;
438  const Option<JSON::Object> config;
439 };
440 
441 #endif // __DOCKER_HPP__
Option< std::vector< std::string > > entrypoint
Definition: docker.hpp:164
Definition: docker.hpp:74
Definition: path.hpp:29
Option< Bytes > memoryReservation
Definition: docker.hpp:205
struct Docker::Device::Access access
Option< Error > validate(const std::string &imageDir)
std::string image
Definition: docker.hpp:254
const Option< pid_t > pid
Definition: docker.hpp:108
std::vector< std::string > arguments
Definition: docker.hpp:257
std::vector< std::string > dnsOpt
Definition: docker.hpp:236
virtual process::Future< Version > version() const
Definition: check.hpp:33
Option< Bytes > memory
Definition: docker.hpp:208
Option< uint64_t > cpuShares
Definition: docker.hpp:199
bool privileged
Definition: docker.hpp:196
Option< std::string > network
Definition: docker.hpp:224
uint32_t containerPort
Definition: docker.hpp:87
constexpr const char * prefix
Definition: os.hpp:96
std::vector< Device > devices
Definition: docker.hpp:242
virtual process::Future< std::vector< Container > > ps(bool all=false, const Option< std::string > &prefix=None()) const
Option< uint64_t > cpuQuota
Definition: docker.hpp:202
Option< std::map< std::string, std::string > > environment
Definition: docker.hpp:166
const std::vector< std::string > dnsSearch
Definition: docker.hpp:131
const bool started
Definition: docker.hpp:112
virtual process::Future< Image > pull(const std::string &directory, const std::string &image, bool force=false) const
constexpr char DEFAULT_DOCKER_HOST_PREFIX[]
Definition: docker.hpp:51
Option< std::string > hostname
Definition: docker.hpp:227
#define STDERR_FILENO
Definition: windows.hpp:155
Definition: duration.hpp:32
std::vector< std::string > dns
Definition: docker.hpp:230
virtual process::Future< Nothing > kill(const std::string &containerName, int signal) const
virtual process::Future< Container > inspect(const std::string &containerName, const Option< Duration > &retryInterval=None()) const
Access()
Definition: docker.hpp:76
Definition: json.hpp:158
Docker(const std::string &_path, const std::string &_socket, const Option< JSON::Object > &_config)
Definition: docker.hpp:334
Definition: docker.hpp:91
Definition: docker.hpp:69
Represents a fork() exec()ed subprocess.
Definition: subprocess.hpp:44
void json(JSON::ObjectWriter *writer, const asV1Protobuf &protobuf)
static IO FD(int_fd fd, IO::FDType type=IO::DUPLICATED)
bool write
Definition: docker.hpp:79
const std::vector< std::string > dns
Definition: docker.hpp:125
const Option< std::string > ipAddress
Definition: docker.hpp:116
#define STDOUT_FILENO
Definition: windows.hpp:154
const std::vector< std::string > dnsOptions
Definition: docker.hpp:128
bool mknod
Definition: docker.hpp:80
Represents a POSIX or Windows file system path and offers common path manipulations.
Definition: path.hpp:212
Definition: duration.hpp:207
Describes how the I/O is redirected for stdin/stdout/stderr.
Definition: subprocess.hpp:62
std::vector< std::string > dnsSearch
Definition: docker.hpp:233
std::vector< std::string > additionalOptions
Definition: docker.hpp:251
Definition: future.hpp:74
const std::string output
Definition: docker.hpp:98
static Try< process::Owned< Docker > > create(const std::string &path, const std::string &socket, bool validate=true, const Option< JSON::Object > &config=None())
Protocol< PromiseRequest, PromiseResponse > promise
uint32_t hostPort
Definition: docker.hpp:86
std::vector< PortMapping > portMappings
Definition: docker.hpp:239
Option< std::string > protocol
Definition: docker.hpp:88
Definition: docker.hpp:57
std::map< std::string, std::string > env
Definition: docker.hpp:215
URI image(const std::string &repository, const std::string &reference, const std::string &registry, const Option< std::string > &scheme=None(), const Option< int > &port=None())
Definition: docker.hpp:30
Definition: none.hpp:27
Option< std::string > volumeDriver
Definition: docker.hpp:221
const std::vector< Device > devices
Definition: docker.hpp:122
Definition: version.hpp:41
virtual Try< Nothing > validateVersion(const Version &minVersion) const
Option< int > oomScoreAdj
Definition: docker.hpp:211
const std::string id
Definition: docker.hpp:101
virtual std::string getSocket()
Definition: docker.hpp:327
virtual std::string getPath()
Definition: docker.hpp:322
virtual ~Docker()
Definition: docker.hpp:67
Path hostPath
Definition: docker.hpp:71
Definition: docker.hpp:84
const std::string name
Definition: docker.hpp:104
bool read
Definition: docker.hpp:78
virtual process::Future< Option< int > > run(const RunOptions &options, const process::Subprocess::IO &_stdout=process::Subprocess::FD(STDOUT_FILENO), const process::Subprocess::IO &_stderr=process::Subprocess::FD(STDERR_FILENO)) const
std::vector< std::string > volumes
Definition: docker.hpp:218
Definition: spec.hpp:35
Definition: owned.hpp:36
Option< std::string > entrypoint
Definition: docker.hpp:245
Option< std::string > name
Definition: docker.hpp:248
const Option< std::string > ip6Address
Definition: docker.hpp:120
Definition: docker.hpp:177
Path containerPath
Definition: docker.hpp:72
virtual process::Future< Nothing > rm(const std::string &containerName, bool force=false) const
virtual process::Future< Nothing > stop(const std::string &containerName, const Duration &timeout=Seconds(0), bool remove=false) const
Definition: docker.hpp:159
Definition: future.hpp:58