docker

2020-05-29T15:20:08.069200Z

I'm in the process of migrating to version 1.0.1 of clj-docker-client and am having issues understanding how exec works now. I'm running this:

(docker/invoke
  client
  {:op               :ContainerExec
   :params           {:id         "couchbase"
                      :execConfig {:Cmd [,,,]}}})
Which returns an Id, but I don't think this has run anything in the container. This is the function that I used to have before upgrading:
(defn exec
  "Run a command inside a Docker container"
  [^DockerClient conn id cmdvec]
  (let [^ExecStartResultCallback callback (ExecStartResultCallback. System/out System/err)
        ^ExecCreateCmd exec-cmd           (-> conn
                                              (.execCreateCmd id)
                                              (.withAttachStdout true)
                                              (.withAttachStderr true)
                                              (.withCmd (into-array String cmdvec)))]
    (-> conn
        (.execStartCmd (.getId ^ExecCreateCmdResponse (.exec exec-cmd)))
        ^ExecStartResultCallback (.exec callback)
        .awaitCompletion)))

2020-05-29T15:52:24.069300Z

Ok, I think I've got it. The invoke above creates an Exec instance that must be executed, and the result is a stream that can be watched if desired. Here's the working function:

(defn exec
  "Run command inside docker container"
  [client image-id cmd]
  (let [instance    (docker/invoke client
                                   {:op     :ContainerExec
                                    :params {:id         image-id
                                             :execConfig {:AttachStdout true
                                                          :Cmd          cmd}}})
        exec-client (docker/client {:category :exec
                                    :conn     {:uri "unix:///var/run/docker.sock"}})]
    (docker/invoke exec-client
                   {:as     :stream
                    :op     :ExecStart
                    :params {:id              (:Id instance)
                             :execStartConfig {}}})))

2020-05-29T15:55:33.069700Z

I did have to create an :exec client, I don't know if there's a way around that. It is a bit odd that I can create the Exec instance with the :containers client, but not start it. ¯\(ツ)

lispyclouds 2020-05-29T16:56:36.069900Z

@jvtrigueros yes the way youre doing it is correct. The reasoning is that clj-docker-client is now a very thin layer on top of docker's REST API, documented here https://docs.docker.com/engine/api/v1.40 To create the exec instance the api is /containers/{id}/exec hence uses the containers client: https://docs.docker.com/engine/api/v1.40/#operation/ContainerExec To start it the API is /exec/{id}/start: https://docs.docker.com/engine/api/v1.40/#operation/ExecStart

lispyclouds 2020-05-29T16:57:27.070500Z

the categories are the prefixes in the API paths: /images, /containers, /_ping etc

2020-05-29T16:57:35.070700Z

Right, that's how I was able to piece it together. Thanks for following up!

lispyclouds 2020-05-29T16:58:25.070900Z

you can have a look at the (maybe more more searchable) vendored swagger YAML: https://github.com/into-docker/clj-docker-client/blob/master/resources/clj_docker_client/api/latest.yaml

lispyclouds 2020-05-29T17:00:09.071300Z

hopefully this simplification and reducing layers between you and docker helps! thats what allowed it to reach 1.0 too 😄

2020-05-29T17:00:52.071500Z

Yes, that does make it much much simpler. It's straightforward to make the connection. Although, I did have a question regarding (docker/doc ,,,)

2020-05-29T17:01:02.071700Z

For example:

(docker/doc client :ContainerExec)
=>
{:doc "Create an exec instance\nRun a command inside a running container.",
 :params ({:name "execConfig"} {:name "id", :type "string"})}

2020-05-29T17:01:20.071900Z

Id tells me it's a type string, but execConfig doesn't.

2020-05-29T17:01:50.072100Z

Going to the YAML file, I was able to see that it was an object type and was able to see which keys were needed, is there a different way to drill down?

lispyclouds 2020-05-29T17:02:51.072300Z

yeah thats something ive been planning to work on, do a proper spec based info and data generation: https://github.com/into-docker/clj-docker-client/issues/15

lispyclouds 2020-05-29T17:03:07.072600Z

this is the best it can for now unfortunately 😞

2020-05-29T17:03:40.072800Z

So if it's missing a type, it is implicitly object?

lispyclouds 2020-05-29T17:03:42.073Z

finding it hard to find time for this, some PRs would be really swiftly merged though! 😄

lispyclouds 2020-05-29T17:03:46.073200Z

yes

2020-05-29T17:03:51.073400Z

Ah gotcha

lispyclouds 2020-05-29T17:04:35.073600Z

you can try to use REBL if you want

lispyclouds 2020-05-29T17:04:58.073800Z

you can create a client and use REBL to drill down in the UI

lispyclouds 2020-05-29T17:05:11.074Z

better doc and help IMO

2020-05-29T17:05:24.074200Z

I'll have to give that a shot, I've yet to try out REBL 😛

lispyclouds 2020-05-29T17:06:07.074700Z

you can very very minutely inspect the client thats created here 😄

2020-05-29T17:06:43.074900Z

Sorry it took me this long to get up to speed with the latest version, it's much much nicer now 🙂 No more dealing with Java interop, just data!

lispyclouds 2020-05-29T17:09:49.075100Z

awesome! hope its useful

lispyclouds 2020-05-29T17:10:10.075300Z

this is how REBL drilling down looks like 😄

2020-05-29T17:36:13.075700Z

oooo nice!