is it possible using Pulumi to build from a Docker...
# general
b
is it possible using Pulumi to build from a Dockerfile and then run a docker container with the built image, all locally? All my attempts failed with problems related to docker registry. It seems that
@pulumi/docker
requires me to have a proper docker registry running (which I would like to avoid for dummy localhost deployments). I even started setting up a local docker registry in my machine, but the struggle to setup TLS and authentication on it made me think that there must be an easier path for this 😕
w
This blog post (and the DockerCon talk that it references) showed off some patterns for this. Does anything there help? https://www.pulumi.com/blog/pulumi-and-docker-development-to-production/
g
I wrote my own "docker builder" utility function because I didn't really want docker images registered as resources and I didn't like that @pulumi/docker also builds the image during a preview (which makes the preview kinda slow). Here's a snippet from my code to do that:
Copy code
import { execSync } from "child_process";

const bash = (cmd: string, cwd?: string) => execSync(cmd, { encoding: "utf8", stdio: "inherit", cwd });

const bashSilent = (cmd: string) => execSync(cmd, { encoding: "utf8" });

const gitSha1 = process.env.GIT_SHA1 ?? bashSilent("git rev-parse HEAD").trim();

import * as pulumi from "@pulumi/pulumi";
import { once } from "remeda";
import { baseImageRef } from "../src/constants";

function buildImageLocally() {
  const imageRef = baseImageRef + `:built-from-local`;
  bash(`DOCKER_BUILDKIT=1 docker build . -t ${imageRef}`, __dirname + "/../../..");
  bash(`docker push ${imageRef}`);
  const pinnedImageRef = bashSilent(`docker inspect --format='{{index .RepoDigests 0}}' ${imageRef}`);
  return pinnedImageRef.trim();
}

/* 
This determines the docker image ref to inject into the kubernetes resources.
There are basically 3 cases:
1. CIRCLE_SHA1 environment variable is set which means this deploy runs in circleci. We then just use the CIRCLE_SHA1 to construct an image ref which points to the image built already by circleci.
2. SKIP_BUILD is set which means the user explicitly wanted to skip local image build. We can then use then construct an image ref using the gitSha1 of the latest HEAD commit.
   Note this doesn't work well if you have changed the application code locally since it won't create a new docker image containing your changes.
3. Nothing is set. If this is a dry-run (i.e. pulumi preview) we only return a preliminary image ref. If this is not a dry run we try to build and push and image ad-hoc by running a few docker commands.
*/
export const getDockerImageRef = once(() => {
  if (process.env.CIRCLE_SHA1) {
    return baseImageRef + ":" + process.env.CIRCLE_SHA1;
  } else if (process.env.SKIP_BUILD) {
    return baseImageRef + ":" + gitSha1;
  } else if (pulumi.runtime.isDryRun()) {
    return `${baseImageRef}@sha256:<computed value>`;
  } else {
    return buildImageLocally();
  }
});
The places where I use need to use the image I then simply call
getDockerImageRef()
and it's doing the right thing for me. Should be easy to modify to skip the push step etc.
b
@white-balloon-205 my code is actually based on that one, but there all the images are public/remote. There is no
docker build
involved. @glamorous-printer-66548 I will give your code a try. Would you have some usage example to share? 🙂
g
idk, I use that utility function for deploying to kubernetes from local and just call that
getDockerImageRef()
on the
image
property of a k8s deployment template. i.e.
image: getDockerImageRef()
. I only build, but not run the image locally although that should be relatively easy to do as well. What's your use-case actually?
b
my use case is very simple. I have a nextjs application which I want to run locally and later on deploy to my cloud. I was hoping that pulumi could be responsible for setting up both environments. The code I wrote is very simple, but doesn't achieve its goal because
docker.Container
requires a registry:
Copy code
const image = new docker.Image(
    `${name}-image`,
    {
      imageName: `${name}-image`,
      build: {
        args: args.buildArgs,
        context: args.context,
        dockerfile: args.dockerfile,
      },
      skipPush: true,
    },
  )

const container = new docker.Container(
    `${name}-container`,
    {
        image: image.imageName,
        ports: [{ internal: 5000, external: args.port }],
    },
)
@geekflyer I was checking your code and as you said it builds and tag the image, but doesn't run the container. If you try to run a
new docker.Container
using that image created with your code but without pushing it to registry, it will fail as well
in other words, docker is building the images fine. It's the
docker.Container
that can't run them
I think I start getting now.
@pulumi/docker
is just a wrapper around terraform's docker provider, correct? According to https://www.terraform.io/docs/providers/docker/r/container.html there is no way to skip the pull of images there, even though in Ansible it's possible (https://docs.ansible.com/ansible/latest/modules/docker_container_module.html#parameter-pull). Does it mean Pulumi can't support that feature either? 😥
g
Maybe look into using a Dynamic provider and simply invoke docker commands in that provider (without @pulumi/docker) https://www.pulumi.com/docs/intro/concepts/programming-model/#dynamicproviders
b
thanks for the suggestions @glamorous-printer-66548. I will take a look into that and see if I manage to solve my case with it. For now, I decided to go ahead and reported it as an issue at https://github.com/pulumi/pulumi-docker/issues/148 since I imagine that many more people will face the same problem eventually