You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@openwhisk.apache.org by al...@apache.org on 2020/04/21 03:26:20 UTC

[openwhisk-wskdebug] branch dockerode created (now ff27527)

This is an automated email from the ASF dual-hosted git repository.

alexkli pushed a change to branch dockerode
in repository https://gitbox.apache.org/repos/asf/openwhisk-wskdebug.git.


      at ff27527  use docker api client dockerode instead of `docker` child process

This branch includes the following new commits:

     new ff27527  use docker api client dockerode instead of `docker` child process

The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.



[openwhisk-wskdebug] 01/01: use docker api client dockerode instead of `docker` child process

Posted by al...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

alexkli pushed a commit to branch dockerode
in repository https://gitbox.apache.org/repos/asf/openwhisk-wskdebug.git

commit ff27527282946e9cce565c82c7bc39ce3c3d81dd
Author: Alexander Klimetschek <ak...@adobe.com>
AuthorDate: Mon Apr 20 20:09:05 2020 -0700

    use docker api client dockerode instead of `docker` child process
    
    - improves performance slightly as no child process execution is required
    - easier to use API than building cli arguments & parsing stdout
---
 package-lock.json | 212 ++++++++++++++++++++++++++++++++++++++++++++++++++++--
 package.json      |   1 +
 src/debugger.js   |  10 ++-
 src/invoker.js    | 127 ++++++++++++++++++++++++--------
 src/log.js        |   6 ++
 5 files changed, 319 insertions(+), 37 deletions(-)

diff --git a/package-lock.json b/package-lock.json
index ae04f84..9912708 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -462,6 +462,14 @@
             "integrity": "sha1-7L0W+JSbFXGDcRsb2jNPN4QBhas=",
             "dev": true
         },
+        "asn1": {
+            "version": "0.2.4",
+            "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz",
+            "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==",
+            "requires": {
+                "safer-buffer": "~2.1.0"
+            }
+        },
         "astral-regex": {
             "version": "1.0.0",
             "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz",
@@ -479,11 +487,34 @@
             "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
             "dev": true
         },
+        "base64-js": {
+            "version": "1.3.1",
+            "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.1.tgz",
+            "integrity": "sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g=="
+        },
+        "bcrypt-pbkdf": {
+            "version": "1.0.2",
+            "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz",
+            "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=",
+            "requires": {
+                "tweetnacl": "^0.14.3"
+            }
+        },
         "binary-extensions": {
             "version": "2.0.0",
             "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.0.0.tgz",
             "integrity": "sha512-Phlt0plgpIIBOGTT/ehfFnbNlfsDEiqmzE2KRXoX1bLIlir4X/MR+zSyBEkL05ffWgnRSf/DXv+WrUAVr93/ow=="
         },
+        "bl": {
+            "version": "4.0.2",
+            "resolved": "https://registry.npmjs.org/bl/-/bl-4.0.2.tgz",
+            "integrity": "sha512-j4OH8f6Qg2bGuWfRiltT2HYGx0e1QcBTrK9KAHNMwMZdQnDZFk0ZSYIpADjYCB3U12nicC5tVJwSIhwOWjb4RQ==",
+            "requires": {
+                "buffer": "^5.5.0",
+                "inherits": "^2.0.4",
+                "readable-stream": "^3.4.0"
+            }
+        },
         "brace-expansion": {
             "version": "1.1.11",
             "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
@@ -508,6 +539,20 @@
             "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==",
             "dev": true
         },
+        "buffer": {
+            "version": "5.6.0",
+            "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.6.0.tgz",
+            "integrity": "sha512-/gDYp/UtU0eA1ys8bOs9J6a+E/KWIY+DZ+Q2WESNUA0jFRsJOc0SNUO6xJ5SGA1xueg3NL65W6s+NY5l9cunuw==",
+            "requires": {
+                "base64-js": "^1.0.2",
+                "ieee754": "^1.1.4"
+            }
+        },
+        "buffer-from": {
+            "version": "1.1.1",
+            "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz",
+            "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A=="
+        },
         "caching-transform": {
             "version": "4.0.0",
             "resolved": "https://registry.npmjs.org/caching-transform/-/caching-transform-4.0.0.tgz",
@@ -567,6 +612,11 @@
                 "readdirp": "~3.3.0"
             }
         },
+        "chownr": {
+            "version": "1.1.4",
+            "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz",
+            "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg=="
+        },
         "clean-stack": {
             "version": "2.2.0",
             "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz",
@@ -645,6 +695,17 @@
             "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
             "dev": true
         },
+        "concat-stream": {
+            "version": "2.0.0",
+            "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-2.0.0.tgz",
+            "integrity": "sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==",
+            "requires": {
+                "buffer-from": "^1.0.0",
+                "inherits": "^2.0.3",
+                "readable-stream": "^3.0.2",
+                "typedarray": "^0.0.6"
+            }
+        },
         "convert-source-map": {
             "version": "1.7.0",
             "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.7.0.tgz",
@@ -733,6 +794,27 @@
             "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==",
             "dev": true
         },
+        "docker-modem": {
+            "version": "2.1.2",
+            "resolved": "https://registry.npmjs.org/docker-modem/-/docker-modem-2.1.2.tgz",
+            "integrity": "sha512-fwlfnsK9WV+m+qc/NZCiGt+oYAMjmCUeir0a/l3oHb0yc8FhRAucdwT4htKD3aLtV+1w2syQePH9pQFxsq1GFA==",
+            "requires": {
+                "debug": "^4.1.1",
+                "readable-stream": "^3.5.0",
+                "split-ca": "^1.0.1",
+                "ssh2": "^0.8.7"
+            }
+        },
+        "dockerode": {
+            "version": "3.2.0",
+            "resolved": "https://registry.npmjs.org/dockerode/-/dockerode-3.2.0.tgz",
+            "integrity": "sha512-C+y/W4Kks7YLBsfUOTMkk1IVilb4cdj+rE+UZ5hnE+rpcn2frSs7kX+6H8GteTqHcv8sln+GyxuP1qdno3IzIw==",
+            "requires": {
+                "concat-stream": "~2.0.0",
+                "docker-modem": "^2.1.0",
+                "tar-fs": "~2.0.1"
+            }
+        },
         "doctrine": {
             "version": "3.0.0",
             "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz",
@@ -755,6 +837,14 @@
                 "iconv-lite": "~0.4.13"
             }
         },
+        "end-of-stream": {
+            "version": "1.4.4",
+            "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz",
+            "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==",
+            "requires": {
+                "once": "^1.4.0"
+            }
+        },
         "es-abstract": {
             "version": "1.17.5",
             "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.5.tgz",
@@ -1202,6 +1292,11 @@
             "integrity": "sha512-33X7H/wdfO99GdRLLgkjUrD4geAFdq/Uv0kl3HD4da6HDixd2GUg8Mw7dahLCV9r/EARkmtYBB6Tch4EEokFTQ==",
             "dev": true
         },
+        "fs-constants": {
+            "version": "1.0.0",
+            "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz",
+            "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow=="
+        },
         "fs-extra": {
             "version": "8.1.0",
             "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz",
@@ -1402,6 +1497,11 @@
                 "safer-buffer": ">= 2.1.2 < 3"
             }
         },
+        "ieee754": {
+            "version": "1.1.13",
+            "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz",
+            "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg=="
+        },
         "ignore": {
             "version": "4.0.6",
             "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz",
@@ -1452,8 +1552,7 @@
         "inherits": {
             "version": "2.0.4",
             "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
-            "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
-            "dev": true
+            "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
         },
         "inquirer": {
             "version": "7.1.0",
@@ -1971,6 +2070,11 @@
                 "minimist": "^1.2.5"
             }
         },
+        "mkdirp-classic": {
+            "version": "0.5.2",
+            "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.2.tgz",
+            "integrity": "sha512-ejdnDQcR75gwknmMw/tx02AuRs8jCtqFoFqDZMjiNxsu85sRIJVXDKHuLYvUUPRBUtV2FpSZa9bL1BUa3BdR2g=="
+        },
         "mocha": {
             "version": "7.1.1",
             "resolved": "https://registry.npmjs.org/mocha/-/mocha-7.1.1.tgz",
@@ -2472,7 +2576,6 @@
             "version": "1.4.0",
             "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
             "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
-            "dev": true,
             "requires": {
                 "wrappy": "1"
             }
@@ -2690,6 +2793,15 @@
             "integrity": "sha512-vGrhOavPSTz4QVNuBNdcNXePNdNMaO1xj9yBeH1ScQPjk/rhg9sSlCXPhMkFuaNNW/syTvYqsnbIJxMBfRbbag==",
             "dev": true
         },
+        "pump": {
+            "version": "3.0.0",
+            "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz",
+            "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==",
+            "requires": {
+                "end-of-stream": "^1.1.0",
+                "once": "^1.3.1"
+            }
+        },
         "punycode": {
             "version": "2.1.1",
             "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
@@ -2702,6 +2814,16 @@
             "integrity": "sha512-pVzZdDpWwWqEVVLshWUHjNwuVP7SfcmPraYuqocJp1yo2U1R7P+5QAfDhdItkuoGqIBnBYrtPp7rEPqDn9HlZA==",
             "dev": true
         },
+        "readable-stream": {
+            "version": "3.6.0",
+            "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
+            "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
+            "requires": {
+                "inherits": "^2.0.3",
+                "string_decoder": "^1.1.1",
+                "util-deprecate": "^1.0.1"
+            }
+        },
         "readdirp": {
             "version": "3.3.0",
             "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.3.0.tgz",
@@ -2922,12 +3044,35 @@
                 }
             }
         },
+        "split-ca": {
+            "version": "1.0.1",
+            "resolved": "https://registry.npmjs.org/split-ca/-/split-ca-1.0.1.tgz",
+            "integrity": "sha1-bIOv82kvphJW4M0ZfgXp3hV2kaY="
+        },
         "sprintf-js": {
             "version": "1.0.3",
             "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
             "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=",
             "dev": true
         },
+        "ssh2": {
+            "version": "0.8.9",
+            "resolved": "https://registry.npmjs.org/ssh2/-/ssh2-0.8.9.tgz",
+            "integrity": "sha512-GmoNPxWDMkVpMFa9LVVzQZHF6EW3WKmBwL+4/GeILf2hFmix5Isxm7Amamo8o7bHiU0tC+wXsGcUXOxp8ChPaw==",
+            "requires": {
+                "ssh2-streams": "~0.4.10"
+            }
+        },
+        "ssh2-streams": {
+            "version": "0.4.10",
+            "resolved": "https://registry.npmjs.org/ssh2-streams/-/ssh2-streams-0.4.10.tgz",
+            "integrity": "sha512-8pnlMjvnIZJvmTzUIIA5nT4jr2ZWNNVHwyXfMGdRJbug9TpI3kd99ffglgfSWqujVv/0gxwMsDn9j9RVst8yhQ==",
+            "requires": {
+                "asn1": "~0.2.0",
+                "bcrypt-pbkdf": "^1.0.2",
+                "streamsearch": "~0.1.2"
+            }
+        },
         "stream-events": {
             "version": "1.0.5",
             "resolved": "https://registry.npmjs.org/stream-events/-/stream-events-1.0.5.tgz",
@@ -2937,6 +3082,11 @@
                 "stubs": "^3.0.0"
             }
         },
+        "streamsearch": {
+            "version": "0.1.2",
+            "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-0.1.2.tgz",
+            "integrity": "sha1-gIudDlb8Jz2Am6VzOOkpkZoanxo="
+        },
         "string-width": {
             "version": "4.2.0",
             "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz",
@@ -2989,6 +3139,21 @@
                 "es-abstract": "^1.17.5"
             }
         },
+        "string_decoder": {
+            "version": "1.3.0",
+            "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
+            "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
+            "requires": {
+                "safe-buffer": "~5.2.0"
+            },
+            "dependencies": {
+                "safe-buffer": {
+                    "version": "5.2.0",
+                    "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz",
+                    "integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg=="
+                }
+            }
+        },
         "strip-ansi": {
             "version": "6.0.0",
             "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz",
@@ -3082,6 +3247,29 @@
                 }
             }
         },
+        "tar-fs": {
+            "version": "2.0.1",
+            "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.0.1.tgz",
+            "integrity": "sha512-6tzWDMeroL87uF/+lin46k+Q+46rAJ0SyPGz7OW7wTgblI273hsBqk2C1j0/xNadNLKDTUL9BukSjB7cwgmlPA==",
+            "requires": {
+                "chownr": "^1.1.1",
+                "mkdirp-classic": "^0.5.2",
+                "pump": "^3.0.0",
+                "tar-stream": "^2.0.0"
+            }
+        },
+        "tar-stream": {
+            "version": "2.1.2",
+            "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.1.2.tgz",
+            "integrity": "sha512-UaF6FoJ32WqALZGOIAApXx+OdxhekNMChu6axLJR85zMMjXKWFGjbIRe+J6P4UnRGg9rAwWvbTT0oI7hD/Un7Q==",
+            "requires": {
+                "bl": "^4.0.1",
+                "end-of-stream": "^1.4.1",
+                "fs-constants": "^1.0.0",
+                "inherits": "^2.0.3",
+                "readable-stream": "^3.1.1"
+            }
+        },
         "teeny-request": {
             "version": "6.0.1",
             "resolved": "https://registry.npmjs.org/teeny-request/-/teeny-request-6.0.1.tgz",
@@ -3155,6 +3343,11 @@
             "integrity": "sha512-aZW88SY8kQbU7gpV19lN24LtXh/yD4ZZg6qieAJDDg+YBsJcSmLGK9QpnUjAKVG/xefmvJGd1WUmfpT/g6AJGA==",
             "dev": true
         },
+        "tweetnacl": {
+            "version": "0.14.5",
+            "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz",
+            "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q="
+        },
         "type-check": {
             "version": "0.3.2",
             "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz",
@@ -3170,6 +3363,11 @@
             "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==",
             "dev": true
         },
+        "typedarray": {
+            "version": "0.0.6",
+            "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
+            "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c="
+        },
         "typedarray-to-buffer": {
             "version": "3.1.5",
             "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz",
@@ -3199,6 +3397,11 @@
             "integrity": "sha1-iS/pWWCAXoVRnxzUOJ8stMu3ZS8=",
             "dev": true
         },
+        "util-deprecate": {
+            "version": "1.0.2",
+            "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
+            "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
+        },
         "uuid": {
             "version": "3.4.0",
             "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
@@ -3299,8 +3502,7 @@
         "wrappy": {
             "version": "1.0.2",
             "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
-            "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
-            "dev": true
+            "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
         },
         "write": {
             "version": "1.0.3",
diff --git a/package.json b/package.json
index 3c90c97..f98e612 100644
--- a/package.json
+++ b/package.json
@@ -45,6 +45,7 @@
         "chalk": "^4.0.0",
         "clone": "^2.1.2",
         "debug": "^4.1.1",
+        "dockerode": "^3.2.0",
         "fetch-retry": "^3.1.0",
         "fs-extra": "^8.1.0",
         "isomorphic-fetch": "^2.2.1",
diff --git a/src/debugger.js b/src/debugger.js
index e7d250b..58462ef 100644
--- a/src/debugger.js
+++ b/src/debugger.js
@@ -287,11 +287,19 @@ class Debugger {
         if (this.agentMgr) {
             await this.tryCatch(this.agentMgr.shutdown());
         }
+
+        // ------------< critical removal must happen above this line >---------------
+
+        // in VS Code, we will not run beyond this line upon debug stop.
+        // this is because invoker.stop() will kill the container & thus close the
+        // debug port, upon which VS Code kills the debug process (us)
         if (this.invoker) {
             await this.tryCatch(this.invoker.stop());
-            log.debug(`stopped container: ${this.invoker.name()}`);
         }
+
         if (this.watcher) {
+            // this is not critical on a process exit, only if Debugger is used programmatically
+            // and might be reused for a new run()
             await this.tryCatch(this.watcher.stop());
             log.debug("stopped source file watching");
         }
diff --git a/src/invoker.js b/src/invoker.js
index 32b9d65..7d85134 100644
--- a/src/invoker.js
+++ b/src/invoker.js
@@ -22,6 +22,7 @@ const fetch = require('fetch-retry')(require('isomorphic-fetch'));
 const kinds = require('./kinds/kinds');
 const path = require('path');
 const log = require("./log");
+const Docker = require('dockerode');
 
 const RUNTIME_PORT = 8080;
 const INIT_RETRY_DELAY_MS = 100;
@@ -32,11 +33,13 @@ const OPENWHISK_DEFAULTS = {
     memory: 256
 };
 
-function execute(cmd, options, debug2) {
+function execute(cmd, options) {
     cmd = cmd.replace(/\s+/g, ' ');
+
+    log.verboseStep(`${cmd}`)
+
     const result = execSync(cmd, options);
 
-    (debug2 || log.debug)(`executed: ${cmd}`);
     if (result) {
         return result.toString().trim();
     } else {
@@ -54,6 +57,39 @@ function resolveValue(value, ...args) {
     }
 }
 
+function asContainerName(name) {
+    // docker container names are restricted to [a-zA-Z0-9][a-zA-Z0-9_.-]*
+
+    // 1. replace special characters with dash
+    name = name.replace(/[^a-zA-Z0-9_.-]+/g, '-');
+    // 2. leading character is more limited
+    name = name.replace(/^[^a-zA-Z0-9]+/g, '');
+    // 3. (nice to have) remove trailing special chars
+    name = name.replace(/[^a-zA-Z0-9]+$/g, '');
+
+    return name;
+}
+
+function addressForContainerPort(containerInfo, port) {
+    if (containerInfo && containerInfo.NetworkSettings && containerInfo.NetworkSettings.Ports) {
+        const ports = containerInfo.NetworkSettings.Ports;
+        // example:
+        // Ports {
+        //   '8080/tcp': [ { HostIp: '0.0.0.0', HostPort: '32812' } ],
+        //   '9229/tcp': [ { HostIp: '0.0.0.0', HostPort: '9229' } ]
+        // }
+        const portEntry = ports[`${port}/tcp`];
+        if (portEntry && Array.isArray(portEntry) && portEntry.length >= 1) {
+            const address = portEntry[0];
+            return `${address.HostIp}:${address.HostPort}`;
+        } else {
+            return null;
+        }
+    } else {
+        return null;
+    }
+}
+
 class OpenWhiskInvoker {
     constructor(actionName, action, options, wskProps, wsk) {
         this.actionName = actionName;
@@ -79,12 +115,14 @@ class OpenWhiskInvoker {
         this.wskProps = wskProps;
         this.wsk = wsk;
 
-        this.containerName = this.asContainerName(`wskdebug-${this.action.name}-${Date.now()}`);
+        this.containerName = asContainerName(`wskdebug-${this.action.name}-${Date.now()}`);
+        this.docker = new Docker();
     }
 
     async checkIfDockerAvailable() {
         try {
-            execute("docker info", {stdio: 'ignore'});
+            await this.docker.info();
+            log.debug("docker - availability check")
         } catch (e) {
             throw new Error("Docker not running on local system. A local docker environment is required for the debugger.")
         }
@@ -190,8 +228,10 @@ class OpenWhiskInvoker {
         await this.checkIfDockerAvailable();
 
         try {
-            execute(`docker inspect --type=image ${this.image} 2> /dev/null`);
+            await this.docker.getImage(this.image).inspect();
+            debug2(`docker - image inspected, is present: ${this.image}`)
         } catch (e) {
+            debug2(`docker - image inspected, not found: ${this.image}`)
             // make sure the user can see the image download process as part of docker run
             showDockerRunOutput = true;
             log.warn(`
@@ -208,10 +248,42 @@ class OpenWhiskInvoker {
 `);
         }
 
+        // console.log(this.debug.command);
+        // console.log(this.debug.command.split(" "));
+
+        // TODO: switch docker run to dockerode.run()
+        //       - find the minimal HostConfig that works for the below run options
+        //         https://docs.docker.com/engine/api/v1.37/#operation/ContainerCreate
+        //         https://github.com/apocas/dockerode/issues/257
+        //         https://github.com/apocas/dockerode/blob/master/lib/docker.js#L1442
+        //         https://medium.com/@johnnyeric/how-to-reproduce-command-docker-run-via-docker-remote-api-with-node-js-5918d7b221ea
+        //       - kinds/nodejs.js has to switch from docker args to HostConfig map for -e and -v
+        //       - --docker-args (this.dockerArgsFromUser) must be parsed and turned into HostConfig
+        //       - replaces docker logs call as well, using streams to pass and write into sdtout/err
+        //         - allows to intercept logging using our log.log() & log.error() calls (?)
+        //         - also must use global.mochaLogFile
+        //        - no stdin needed
+        //        - returns dockerode container object (store as this.container)
+        //        - call this.container.kill() on it to get rid of it (already done in stop())
+
+        // await this.docker.run(
+        //     this.image,
+        //     [ 'sh', '-c', ...this.debug.command.split(" ") ],
+        //     showDockerRunOutput ? [process.stdout] : [],
+        //     {
+        //         HostConfig: {
+        //             AutoRemove: true,
+        //             PortBindings: {
+        //                 [`${RUNTIME_PORT}/tcp`]: [{ HostPort: RUNTIME_PORT }]
+        //             }
+        //         }
+        //     }
+        // );
+        // log.debug("docker - run");
         execute(
             `docker run
                 -d
-                --name ${this.name()}
+                --name ${this.containerName}
                 --rm
                 -m ${this.memory}
                 -p ${RUNTIME_PORT}
@@ -222,11 +294,16 @@ class OpenWhiskInvoker {
                 ${this.debug.command}
             `,
             // live stream view for docker image download output
-            { stdio: showDockerRunOutput ? "inherit" : null },
-            debug2
+            { stdio: showDockerRunOutput ? "inherit" : null }
         );
+        debug2(`docker - started container ${this.containerName}`);
 
-        this.containerRunning = true;
+        this.container = this.docker.getContainer(this.containerName);
+
+        // ask docker for the exposed IP and port of the RUNTIME_PORT on the container
+        const containerInfo = await this.container.inspect();
+        debug2(`docker - retrieved container metadata`);
+        this.containerURL = `http://${addressForContainerPort(containerInfo, RUNTIME_PORT)}`;
 
         log.stopSpinner();
         spawn("docker", ["logs", "-t", "-f", this.name()], {
@@ -236,6 +313,7 @@ class OpenWhiskInvoker {
                 global.mochaLogFile || "inherit"  // stderr
             ]
         });
+        log.debug(`docker - trailing logs`);
     }
 
     getSourcePath() {
@@ -308,40 +386,27 @@ class OpenWhiskInvoker {
     }
 
     async stop() {
-        if (this.containerRunning) {
-            execute(`docker kill ${this.name()}`);
+        if (this.container) {
+            // log this here for VS Code, will be the last visible log message since
+            // we will be killed by VS code after the container is gone after the kill()
+            log.log(`Stopping container ${this.name()}.`);
+            await this.container.kill();
+            delete this.container;
+            log.debug(`docker - stopped container ${this.name()}`);
         }
     }
 
     name() {
-        return this.containerName;
+        return this.container ? this.container.id : "";
     }
 
     url() {
-        if (!this.containerURL) {
-            // ask docker for the exposed IP and port of the RUNTIME_PORT on the container
-            const host = execute(`docker port ${this.name()} ${RUNTIME_PORT}`);
-            this.containerURL = `http://${host}`;
-        }
-        return this.containerURL;
+        return this.containerURL || "";
     }
 
     timeout() {
         return this.action.limits.timeout || OPENWHISK_DEFAULTS.timeout;
     }
-
-    asContainerName(name) {
-        // docker container names are restricted to [a-zA-Z0-9][a-zA-Z0-9_.-]*
-
-        // 1. replace special characters with dash
-        name = name.replace(/[^a-zA-Z0-9_.-]+/g, '-');
-        // 2. leading character is more limited
-        name = name.replace(/^[^a-zA-Z0-9]+/g, '');
-        // 3. (nice to have) remove trailing special chars
-        name = name.replace(/[^a-zA-Z0-9]+$/g, '');
-
-        return name;
-    }
 }
 
 module.exports = OpenWhiskInvoker;
diff --git a/src/log.js b/src/log.js
index fc39e25..8c13932 100644
--- a/src/log.js
+++ b/src/log.js
@@ -117,6 +117,12 @@ module.exports = {
         }
     },
 
+    verboseStep: function(...args) {
+        if (this.isVerbose) {
+            this.step(...args);
+        }
+    },
+
     verboseWrite: function(text) {
         if (this.isVerbose) {
             process.stdout.write(text);