clojure

2026-05-22T15:51:40.195959Z

Hi, I've just been porting a Python script to Clojure, and I need to package it up into a Docker image to run as an AWS ECS task. Are there any guidelines for building Docker images for Clojure projects? This is the Dockerfile I came up with, but I'd welcome any pointers if there's a better way:

FROM  AS builder

WORKDIR /build
COPY build.clj deps.edn /build
COPY src /build/src
RUN clojure -T:build ci

FROM 
RUN apk add git git-lfs aws-cli
WORKDIR /srv/bitbucket-backups
COPY --from=builder /build/target/com.metail/bitbucket-backups.jar .
RUN adduser -D default
USER default
CMD ["/opt/java/openjdk/bin/java", "-jar", "bitbucket-backups.jar"]

2026-05-23T14:48:33.702609Z

Just a note to confirm that the Cognitect AWS API is working just fine for my ECS task. I added debugging to the code to check the environment and cross-referenced that with the credentials impl in the Cognitect API, everything looked like it should work, so I added an explicit HTTP GET request for the credentials to debug the problem but found...no problem! I've no idea what caused the error I saw yesterday: put it down to a wetware issue.

p-himik 2026-05-22T16:24:37.313849Z

FWIW it looks reasonable to me. There's not much to it.

2026-05-22T16:25:32.129949Z

Thanks, that's encouraging!

p-himik 2026-05-22T16:26:33.893539Z

I don't know how ECS tasks work and what their requirements are, but my Clojure apps that use Docker run directly from sources inside a container, so I don't even have build.clj. :) No AOT at all.

lukasz 2026-05-22T16:29:05.069599Z

looks good, I've been shipping uberjars in Docker to ECS more or less the same way

2026-05-22T16:30:34.152359Z

@lukaszkorecki have you used the Cognitect AWS API in ECS? My ECS task is failing to retrieve credentials and I'm wondering if ECS credentials are supported or if I did something wrong.

lukasz 2026-05-22T16:33:35.990729Z

it's been few years ago, so that's important to keep in mind - we were using a mix of Cognitect libs for APIs, and AWS SDK for interacting with S3 and couple of other services that needed better IO perf

2026-05-22T16:33:49.223369Z

Hmm, looking at the source code it appears to be supported so maybe an error at my end.

lukasz 2026-05-22T16:33:50.275849Z

I had to write a custom authorizer to use ECS (and AWS SSO locally) creds

lukasz 2026-05-22T16:34:12.439039Z

let me dig it out - it probably doesn't work anymore, but might be salvageable - I don't work with AWS anymore

👍 1
2026-05-22T16:42:46.230809Z

Thanks. I'm comparing your code with the Cognitect library (which now has support for ECS credentials), it looks similar. but there might be some subtlety in the env vars. I'll add some debugging to my code to make sure the expected environment variables are set.

Joe Lane 2026-05-22T18:26:56.741319Z

Make sure you're using a recent version of aws-api, I seem to remember bumping into this ECS/container problem and it ended up w/ a patch to aws-api. I just looked at the changelog and can't seem to find the specific issue, but AWS_EC2_METADATA_SERVICE_ENDPOINT being related to IMDSv2 seems to ring a bell

olli 2026-05-22T18:49:20.702709Z

On that note, I guess you'd want to do a RUN apk upgrade too, the eclipse-temurin images aren't always up to date and seem a bit slow to patch vulnerable libraries as you may have seen https://hub.docker.com/layers/library/eclipse-temurin/26-jre-alpine/images/sha256-f6227038f5b89d45a98ebf69c964d689a123baa06dc74247e77b8dfeefabcf19

👍 1
➕ 1
lukasz 2026-05-22T18:51:05.823109Z

might not matter here since based on dockerfile it looks like an internal thing, but for prod apps def agree - best if you roll your own internal base images that can be updated without waiting for public ones

2026-05-22T18:52:43.099949Z

Yes, this is internal only, but I will address the security issues. First I need to get it working in ECS.

dpsutton 2026-05-22T23:12:00.419329Z

just wrote two of these conflict handlers. One for vertica shading this in, another for hive bringing in some jakarta activation classes.

(def ^:private gson-conflict-handler
  "vertica-jdbc (and potentially other fat JARs) bundle their own copy of gson classes.
   When these overwrite the correct version from com.google.code.gson/gson, BigQuery's
   error-handling path crashes with NoSuchMethodError on JsonWriter.value(float),
   introduced in gson 2.9.0. This handler ensures the pinned gson version always wins
   regardless of JAR processing order. See #73736."
  {"com/google/gson/.*"
   (fn [{:keys [lib path in]}]
     (if (= lib 'com.google.code.gson/gson)
       {:write {path {:stream in}}}
       nil))})
Found it pretty worthwhile to add a test that builds an uberjar into a temp directory and captures any class conflicts
(let [conflicts (atom [])]
    (clean!)
    (b/uber {:class-dir         class-dir
             :uber-file         uberjar-filename
             :conflict-handlers (merge conflict-handlers
                                       {:default (fn [{:keys [lib path]}]
                                                   (when (str/ends-with? path ".class")
                                                     (swap! conflicts conj {:path path :lib lib}))
                                                   nil)})
             :basis             basis
             :exclude           dependency-ignore-patterns})
    @conflicts)
really helpful to see what kind of nasty jars you might have

💯 1
Steven Lombardi 2026-05-23T01:11:37.422149Z

Nice. Super useful in practice for ruling out potential root causes.

Steven Lombardi 2026-05-23T01:12:13.507469Z

Reminds me of the old days when I was verifying the state of osgi containers. Fun times.

dpsutton 2026-05-23T01:17:13.589869Z

Yeah it's surprising what some drivers can bring in. And it's easy to check once. And then four years later you're not so sure. I added a test that asserts no more class conflicts than the ones we currently have. And then we can start reducing it over time

👍 1
Steven Lombardi 2026-05-23T01:22:05.491439Z

Run time is such a target rich environment for stuff like this, not sure why mainstream is so obsessed with compile time. It certainly has its place but you'd never be able to write something like this.

💯 1
dpsutton 2026-05-26T21:03:11.375319Z

for instance, did you know databricks jdbc shipped arrow classfiles unshaded? https://github.com/databricks/databricks-jdbc/tree/main/src/main/java

Steven Lombardi 2026-05-27T00:37:57.093739Z

Actually, yes, I'm pretty sure I've hit that before when trying to use that same library.

Steven Lombardi 2026-05-27T00:39:12.181849Z

At least, trying to use data bricks as a read source was scrapped early in favor of just routing a Kafka stream my way so I can maintain my own materialized view.

Steven Lombardi 2026-05-27T00:39:38.670169Z

I don't recall the specifics but there was a lot more to it than just janky jar files.

Steven Lombardi 2026-05-27T00:42:03.171619Z

You won't need to defend your conflict detector from me. I've felt the pain myself. It's justified, especially if you're using a ton of Java native libs.

Steven Lombardi 2026-05-27T00:42:42.946359Z

Honestly though this is one of those things that I'd adapt to my liking and make it part of my standard tool kit.

dpsutton 2026-05-27T00:51:20.650209Z

Same. Finding overlapping prefixes in classpath jars is super interesting

Steven Lombardi 2026-05-27T00:55:17.211999Z

If you published it as a configurable docker image, I'm using it.

Steven Lombardi 2026-05-27T00:56:09.535349Z

It gets even more interesting when there's more than one classloader involved 😆