A first look at the vctl utility in VMware Fusion

Last week I updated my version of VMware Fusion to 11.5.6. If you don’t know about VMware Fusion, it is a VMware product that gives Mac users the ability to run guest virtual machines. One of the new features that I noticed was the inclusion of a new vctl utility (IIRC, it became available first in v11.5.5.).  This is a command line utility for the Nautilus Container Engine which is now part of VMware Fusion. It allows you to work on OCI (Open Container Initiative) containers from your desktop. I decided to take a closer look, and do a few simple container tasks just to see it in action. From what I understand, starting the Nautilus Container Engine will launch a very lightweight virtual machine (CRX) based on VMware Photon OS. This is very similar to how PodVMs are constructed in vSphere with Kubernetes (You can find more CRX details in this earlier blog post on Project Pacific). Once that is up and running, you will be able to use vctl to do various container operations. Let’s have a look.

Getting started

vctl is installed with VMware Fusion. You don’t need to do anything else. Simply open a terminal on your host system and run vctl without any arguments to display the help output.

chogan@chogan-a01 ~ % vctl

vctl - A CLI tool for the Nautilus Container Engine powered by VMware Fusion
vctl Highlights:
• Build and run OCI containers.
• Push and pull container images between remote registries & local storage.
• Use a lightweight virtual machine (CRX VM) based on VMware Photon OS to host a container. Use 'vctl system config -h' to learn more.
• Easy shell access into virtual machine that hosts container. See 'vctl execvm’.

USAGE:
  vctl COMMAND [OPTIONS]

COMMANDS:
  build       Build a container image from a Dockerfile.
  create      Create a new container from a container image.
  describe    Show details of a container.
  exec        Execute a command within a running container.
  execvm      Execute a command within a running virtual machine that hosts container.
  help        Help about any command.
  images      List container images.
  ps          List containers.
  pull        Pull a container image from a registry.
  push        Push a container image to a registry.
  rm          Remove one or more containers.
  rmi         Remove one or more container images.
  run         Run a new container from a container image.
  start       Start an existing container.
  stop        Stop a container.
  system      Manage the Nautilus Container Engine.
  tag         Tag container images.
  version     Print the version of vctl.

Run 'vctl COMMAND --help' for more information on a command.

OPTIONS:
  -h, --help   Help for vctl

chogan@chogan-a01 ~ %

First we need to start the Container runtime using the vctl system start command.

chogan@chogan-a01 ~ % vctl system start
Preparing storage...
Container storage has been prepared successfully under /Users/chogan/.vctl/storage
Preparing container network, you may be prompted to input password for administrative operations...
Password:*************
Container network has been prepared successfully using vmnet: vmnet9
Launching container runtime...
Container runtime has been started.
chogan@chogan-a01 ~ %

Starting the Container Runtime mounts a volume called “Fusion Container Storage” to the host’s desktop. Now that the runtime is started, let’s try to use vctl to deploy a container image.

Pull & Run a Container Image

For the purpose of this test, I’ll use everyone’s favorite stateless application, nginx. I will first pull it down from the docker hub/registry, and then I will run it using the —name option to give it a unique name, and the -t (tty) option to open a terminal to it, and finally a -d (detach) option so that it runs in the background . Finally I’ll connect the the IP address associated with the image and we should see the default nginx landing page. The container’s rootfs is also mounted to the host so you will observe another volume related to nginx container appear on your desktop.

chogan@chogan-a01 ~ % vctl pull nginx
INFO Pulling from index.docker.io/library/nginx:latest
───                                                                                ──────   ────────
REF                                                                                STATUS   PROGRESS
───                                                                                ──────   ────────
index-sha256:b0ad43f7ee5edbc0effbc14645ae7055e21bc1973aee5150745632a24a752661      Done     100% (1862/1862)
manifest-sha256:179412c42fe3336e7cdc253ad4a2e03d32f50e3037a860cf5edbeb1aaddb915c   Done     100% (1362/1362)
layer-sha256:a5e4a503d449887a0be28a2969149e647460aa6013f9ca90e88491aedf84f24e      Done     100% (666/666)
layer-sha256:cb9a6de05e5a22241e25960c7914f11b56c9070ce28b8f69e899236e0d265c50      Done     100% (26401375/26401375)
layer-sha256:bf59529304463f62efa7179fa1a32718a611528cc4ce9f30c0d1bbc6724ec3fb      Done     100% (27092121/27092121)
config-sha256:4bb46517cac397bdb0bab6eba09b0e1f8e90ddd17cf99662997c3253531136f8     Done     100% (7512/7512)
layer-sha256:9513ea0afb9372e5cabc4070c7adda0e8fc4728e0ad362b349fe233480f2e7d8      Done     100% (600/600)
layer-sha256:b49ea07d2e9310b387436861db613a0a26a98855372e9d5e207660b0de7975a7      Done     100% (899/899)
INFO Unpacking nginx:latest...
INFO done

chogan@chogan-a01 ~ % vctl images
────           ─────────────               ────
NAME           CREATION TIME               SIZE
────           ─────────────               ────
nginx:latest   2020-09-03T10:08:16+01:00   51.0 MiB

chogan@chogan-a01 ~ % vctl run --name cornginx -t -d nginx
INFO container cornginx started and detached from current session

chogan@chogan-a01 ~ % vctl ps
────       ─────          ───────                   ──                ─────   ──────    ─────────────
NAME       IMAGE          COMMAND                   IP                PORTS   STATUS    CREATION TIME
────       ─────          ───────                   ──                ─────   ──────    ─────────────
cornginx   nginx:latest   /docker-entrypoint.s...   192.168.143.128   n/a     running   2020-09-03T10:11:07+01:00

And now if we connect to the IP address assigned to our nginx container, we should see the nginx landing page.

Looks good. Now, since the rootfs has been mounted to the desktop, you can very easily modify some of the container’s file contents. For example, if I wanted to change the landing page above, I could open the nginx volume for the container cornginx on my host desktop and navigate to /usr/share/nginx/html and modify the index.html file:

And now if I modify that index.html to something slightly different to the default, simply adding a newline of text to the bottom of the landing page, and saving it:

I have now updated my landing page in the easiest way possible:

Push an image using vctl to a remote container repository

Let’s now look at how we can use vctl to push images to a remote container repository. I have my own personal repo on docker hub that I will use for this exercise. The steps you will see below are the tagging of my local image with the name of the image I want in my repository. I will then push the image to my repo, and then we will examine my repo to see that the image is indeed there.

chogan@chogan-a01 ~ % vctl ps
────       ─────          ───────                   ──                ─────   ──────    ─────────────
NAME       IMAGE          COMMAND                   IP                PORTS   STATUS    CREATION TIME
────       ─────          ───────                   ──                ─────   ──────    ─────────────
cornginx   nginx:latest   /docker-entrypoint.s...   192.168.143.128   n/a     running   2020-09-03T10:11:07+01:00


chogan@chogan-a01 ~ % vctl tag nginx cormachogan/nginx

chogan@chogan-a01 ~ % vctl push cormachogan/nginx -u cormachogan
Password for cormachogan:**********
INFO pushing image: cormachogan/nginx:latest to index.docker.io/cormachogan/nginx:latest
───                                                                                ──────   ────────
REF                                                                                STATUS   PROGRESS
───                                                                                ──────   ────────
manifest-sha256:179412c42fe3336e7cdc253ad4a2e03d32f50e3037a860cf5edbeb1aaddb915c   Done     100% (1362/1362)
layer-sha256:a5e4a503d449887a0be28a2969149e647460aa6013f9ca90e88491aedf84f24e      Done     100% (666/666)
layer-sha256:9513ea0afb9372e5cabc4070c7adda0e8fc4728e0ad362b349fe233480f2e7d8      Done     100% (600/600)
layer-sha256:cb9a6de05e5a22241e25960c7914f11b56c9070ce28b8f69e899236e0d265c50      Done     100% (26401375/26401375)
config-sha256:4bb46517cac397bdb0bab6eba09b0e1f8e90ddd17cf99662997c3253531136f8     Done     100% (7512/7512)
layer-sha256:bf59529304463f62efa7179fa1a32718a611528cc4ce9f30c0d1bbc6724ec3fb      Done     100% (27092121/27092121)
layer-sha256:b49ea07d2e9310b387436861db613a0a26a98855372e9d5e207660b0de7975a7      Done     100% (899/899)
chogan@chogan-a01 ~ %

And the final check to see that the image made it to my docker hub repo:

Looks good to me.

Pull an image using vctl from a remote container repository

OK – let’s now use the image I just pushed to my personal docker hub repo and use that as a container image rather than pulling directly from docker registry. First, lets remove the current container and the 2 images that currently exist, one locally and one on docker hub.

chogan@chogan-a01 ~ % vctl images
────                       ─────────────               ────
NAME                       CREATION TIME               SIZE
────                       ─────────────               ────
cormachogan/nginx:latest   2020-09-03T10:08:16+01:00   51.0 MiB
nginx:latest               2020-09-03T10:08:16+01:00   51.0 MiB


chogan@chogan-a01 ~ % vctl ps -a
────       ─────          ───────                   ──    ─────   ──────    ─────────────
NAME       IMAGE          COMMAND                   IP    PORTS   STATUS    CREATION TIME
────       ─────          ───────                   ──    ─────   ──────    ─────────────
cornginx   nginx:latest   /docker-entrypoint.s...   n/a   n/a     stopped   2020-09-03T10:11:07+01:00

chogan@chogan-a01 ~ % vctl rm cornginx
────       ──────    ──────
NAME       RESULT    REASON
────       ──────    ──────
cornginx   REMOVED

chogan@chogan-a01 ~ % vctl ps -a
────   ─────   ───────   ──   ─────   ──────   ─────────────
NAME   IMAGE   COMMAND   IP   PORTS   STATUS   CREATION TIME
────   ─────   ───────   ──   ─────   ──────   ─────────────

chogan@chogan-a01 ~ % vctl images
────                       ─────────────               ────
NAME                       CREATION TIME               SIZE
────                       ─────────────               ────
cormachogan/nginx:latest   2020-09-03T10:08:16+01:00   51.0 MiB
nginx:latest               2020-09-03T10:08:16+01:00   51.0 MiB

chogan@chogan-a01 ~ % vctl rmi nginx:latest
────           ──────    ──────
NAME           RESULT    REASON
────           ──────    ──────
nginx:latest   REMOVED

chogan@chogan-a01 ~ % vctl images
────                       ─────────────               ────
NAME                       CREATION TIME               SIZE
────                       ─────────────               ────
cormachogan/nginx:latest   2020-09-03T10:08:16+01:00   51.0 MiB

chogan@chogan-a01 ~ % vctl rmi cormachogan/nginx:latest
────                       ──────    ──────
NAME                       RESULT    REASON
────                       ──────    ──────
cormachogan/nginx:latest   REMOVED

chogan@chogan-a01 ~ % vctl images
────   ─────────────   ────
NAME   CREATION TIME   SIZE
────   ─────────────   ────
chogan@chogan-a01 ~ %

At this point, we have no running containers, and the only image that is available is on my personal docker hub repo. Let’s now pull the image from my docker hub, and run it.

chogan@chogan-a01 ~ % vctl pull cormachogan/nginx:latest
INFO Pulling from index.docker.io/cormachogan/nginx:latest
───                                                                                ──────   ────────
REF                                                                                STATUS   PROGRESS
───                                                                                ──────   ────────
manifest-sha256:179412c42fe3336e7cdc253ad4a2e03d32f50e3037a860cf5edbeb1aaddb915c   Done     100% (1362/1362)
layer-sha256:a5e4a503d449887a0be28a2969149e647460aa6013f9ca90e88491aedf84f24e      Done     100% (666/666)
layer-sha256:cb9a6de05e5a22241e25960c7914f11b56c9070ce28b8f69e899236e0d265c50      Done     100% (26401375/26401375)
config-sha256:4bb46517cac397bdb0bab6eba09b0e1f8e90ddd17cf99662997c3253531136f8     Done     100% (7512/7512)
layer-sha256:bf59529304463f62efa7179fa1a32718a611528cc4ce9f30c0d1bbc6724ec3fb      Done     100% (27092121/27092121)
layer-sha256:9513ea0afb9372e5cabc4070c7adda0e8fc4728e0ad362b349fe233480f2e7d8      Done     100% (600/600)
layer-sha256:b49ea07d2e9310b387436861db613a0a26a98855372e9d5e207660b0de7975a7      Done     100% (899/899)
INFO Unpacking cormachogan/nginx:latest...
INFO done

chogan@chogan-a01 ~ % vctl images
────                       ─────────────               ────
NAME                       CREATION TIME               SIZE
────                       ─────────────               ────
cormachogan/nginx:latest   2020-09-03T14:31:57+01:00   51.0 MiB

chogan@chogan-a01 ~ % vctl run --name mynewnginx -t -d cormachogan/nginx:latest
INFO container mynewnginx started and detached from current session

chogan@chogan-a01 ~ % vctl ps -a
────         ─────                      ───────                   ──                ─────   ──────    ─────────────
NAME         IMAGE                      COMMAND                   IP                PORTS   STATUS    CREATION TIME
────         ─────                      ───────                   ──                ─────   ──────    ─────────────
mynewnginx   cormachogan/nginx:latest   /docker-entrypoint.s...   192.168.143.129   n/a     running   2020-09-03T14:37:54+01:00

Again, this all looks good. A nice addition to VMware Fusion for container workloads.

Running a command on a running container

Previously we saw how a container’s volume appears on the desktop when launch via vctl, and how easy it was to access the container’s file and make changes. But let’s say we wanted to run a command on a container. How would we do that? Well, vctl also comes with an exec argument that allows us to run commands on the selected container. Let’s once again use our nginx container, and use the exec argument run a bash shell on it. In this example I include the -i (interactive) option as well as the -t (tty) option. Check out the help on exec for more details. Like before, I am navigating to the location of the index.html nginx landing page, and displaying the contents.

chogan@chogan-a01 ~ % vctl exec -it mynewnginx /bin/bash
root@mynewnginx:/# cd /usr/share/nginx/html
root@mynewnginx:/usr/share/nginx/html# ls
50x.html  index.html
root@mynewnginx:/usr/share/nginx/html# cat index.html
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
    body {
        width: 35em;
        margin: 0 auto;
        font-family: Tahoma, Verdana, Arial, sans-serif;
    }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>

root@mynewnginx:/usr/share/nginx/html#

One other nice feature that I have read about is in the Fusion 12 Announcement is an extension to vctl which will allow the deployment of a Kind cluster, which is in essence Kubernetes cluster running in containers. I’m very much looking forward to trying that out when I get a chance.

3 Replies to “A first look at the vctl utility in VMware Fusion”

  1. Hi Cormac,

    Your article is inspiring and was a good start point to me.
    Thank you for that.

    I started using vctl on VMWare Fusion 12. It always runs on vmnet8.
    Do you know if it runs on other vmnets

    Kind regards

    1. Correct – it only supports vmnet8 today.

      The team has discussed making that more user-definable – do you have a requirement for such a feature?

    2. I found out that it can be changed.

      For networking, we make it a fixed one (vmnet8) so the user does not need to input sudo crendential to create a new one (create new vmnets needs admin priviledge), but user still can use other vmnet by configuring ~/.vctl/config.yaml
      vmnet: vmnet2

      vmnet2’s nat and dhcp should be enabled to make it work.

Comments are closed.