Fork me on GitHub
#beginners
<
2023-10-19
>
leifericf10:10:32

I'm following https://practical.li/engineering-playbook/continuous-integration/docker/clojure-multi-stage-dockerfile/ to package and deploy my Clojure app. It uses the Docker image clojure:temurin-21-alpine (link) for the build stage.

FROM clojure:temurin-21-alpine AS builder
When I run docker build --tag myorg/myapp:0.1 ., I get the following error:
ERROR: failed to solve: clojure:temurin-21-alpine: no match for platform in manifest sha256:b8309de1785ec59e30ca3a17072be56cc5fd483adf43c0e8176bf842319aa14a: not found
I think this is because no image is available for arm64 (Apple M1 processor). Does an Apple Silicone compatible Docker image exist that one can use to build an Uberjar from Clojure source code?

Tuomas-Matti Soikkeli11:10:36

alpine can be tricky with apple silicon, is there an image with another distro available?

leifericf11:10:21

I found one that works! clojure:temurin-21-tools-deps-jammy

leifericf11:10:06

But now this breaks:

# Add (optional) Alpine packages
RUN apk add --no-cache \
    dumb-init~=1.2.5

leifericf11:10:42

This seems to work with Jammy:

# Add (optional) packages
RUN apt-get update && apt-get install -y \
    dumb-init~=1.2.5
Actually, no, it doesn't:
=> CANCELED [final 2/7] RUN apt-get update && apt-get install -y     dumb-init~=1.2.5    

leifericf11:10:14

I guess I'll just give up on making a Dockerfile that works locally on macOS (Apple Silicone) and in CI/CD 馃槢

leifericf11:10:23

And just run my app through the REPL in Visual Studio Code/Calva or with clj -M -m main in the terminal.

practicalli-johnny12:10:01

@U01PE7630AC For Ubuntu or Debian docker image, remove the version number for the package, i.e.

# Add (optional) packages
RUN apt update && apt install -y dumb-init
Sorry, I dont have an M1 Mac so cannot test on that hardware

practicalli-johnny12:10:11

Note Clojure can be used in a container without dumb-init, especially if the package is the only thing preventing this from working

馃挕 1
leifericf13:10:24

Can I use clojure:temurin-21-jammy for the build stage, and debian:12.2 (or debian:12.2-slim) for the runtime stage, or must I use the same Linux distro for both stages? The only Clojure docker image for arm64 seems to be *-jammy. And I can't find any Debian or Ubuntu images with Clojure.

leifericf13:10:55

For Debian, I also had to change this: RUN addgroup -S practicalli && adduser -S practicalli -G practicalli To this: RUN groupadd -r practicalli && useradd -r -g practicalli practicalli

leifericf13:10:58

In this step:

COPY --from=builder --chown=clojure:clojure /build/myservice.jar /service/myservice.jar
How do you get the name of the .jar file, which was generated with a version number and -standalone in build.clj? :thinking_face:
(def project-config
  "Project configuration to support all tasks"
  (let [library-name 'myorg/myservice
        version (format "0.1.%s" (b/git-count-revs nil))]
    {:library-name    library-name
     :main-namespace  library-name
     :project-version version
     :class-directory "target/classes"
     :project-basis   (b/create-basis)
     :jar-file        (format "target/%s-%s.jar" (name library-name) version)
     :uberjar-file    (format "target/%s-%s-standalone.jar" (name library-name) version)}))
I get this error:
ERROR: failed to solve: failed to compute cache key: failed to calculate checksum of ref 5567f322-3f05-447b-9067-022a6db599ee::awn6vo9r1a6xj4hxa8efbv7zy: "/build/myservice.jar": not found

Ed14:10:28

I think you can use a * file glob in the docker COPY command if that's helpful.

馃憤 1
practicalli-johnny15:10:04

Different images can be used for the build and run stages of the dockerfile. There is a small risk that something is different between the two stages, but as everything runs on top of the JVM, then risk is greatly minimised. I would recommend using the same version of the JVM in build and run stage though.

馃憤 1
practicalli-johnny15:10:53

In the build.clj file I set a key with the uberjar name

(def project-config
  "Project configuration to support all tasks"
  {:class-directory "target/classes"
   :main-namespace  'practicalli/todo-donut.service
   :project-basis   (build-api/create-basis)
   :uberjar-file    "target/practicalli-todo-donut-standalone.jar"})
Then in the uberjar function, I use the key for the name
(defn uberjar
  "Create an archive containing Clojure and the build of the project
  Merge command line configuration to the default project config"
  [options]
  (let [config (merge project-config options)
        {:keys [class-directory main-namespace project-basis uberjar-file]} config]
    (clean "target")
    (build-api/copy-dir {:src-dirs   ["src" "resources"]
                         :target-dir class-directory})

    (build-api/compile-clj {:basis     project-basis
                            :class-dir class-directory
                            :src-dirs  ["src"]})

    (build-api/uber {:basis     project-basis
                     :class-dir class-directory
                     :main      main-namespace
                     :uber-file uberjar-file})))

practicalli-johnny15:10:46

Using the https://practical.li/clojure/clojure-cli/projects/templates/practicalli/ auto-populates this information in the build.clj and Dockerfiles (if you want an example) None of this is tested with Java 21 as its barely been released, but there shouldnt be any issues, except for the changes in the Dockerfiles available. The multi-stage dockerfile guide will be updated to use Java 21 in the next few weeks hopefully, so any feedback is useful.

馃憤 1
leifericf18:10:29

Aha, I see! I鈥檓 not using those project templates and my build.clj was also different. I mistakenly thought the chapter on Docker was standalone. Sorry for the confusion. I'll see if I can get a bare-bones version up and running by referencing your templates.

practicalli-johnny18:10:10

The Dockerfile guide doesnt really assume the underlying details of how the uberjar is built, only that there is a build task to run (via Make or Clojure CLI). The multi-stage dockerfile guide was write when I was using https://github.com/seancorfield/depstar to build the uberjar, so the Docker Ignore patters does not include a build.clj file in the guide. There have been several changes to building uberjars since depstar project was archived, although directly using tools.build does seem to be the simplest approach now. I will add a link to the build.clj approach in https://practical.li/clojure/clojure-cli/projects/package/tools-build/ (after that page is update), as an example way to build the uberjar. There have been quite a few moving parts with Clojure CLI and tools.build, but I believe its a very stable approach now. Thanks for the feedback.

馃挏 1
leifericf18:10:07

Awesome, thanks again for taking the time to help out! Much appreciated. If there is one other piece of feedback: It would be great if the guide used Docker images available on all major platforms, including Apple Silicone, so that it also works locally on most machines. I don't know enough about all the different Linux distros to determine which ones are most appropriate. Debian LTS is known to be more stable and reliable than Ubuntu, but I guess there are several other factors to consider, including image size, etc. And I would be happy to help you test on macOS/arm64.

practicalli-johnny19:10:19

Any further feedback on any Apple hardware is appreciated (unless someone donates Mac hardware to Practicalli :rolling_on_the_floor_laughing: ) All the Practicalli content is currently tested on Ubuntu Linux (Regolith Desktop), although I am moving laptops to Debian & Regolith desktop as I am not keen on snap package approach Ubuntu is moving toward. There is very little difference between Ubuntu and Debian, a few kernel patches mostly, so I doubt there is any noticeable difference in stability. Debian has traditionally supported more hardware platforms, so that seems a valuable reason to shift focus to using Debian in Practicalli content, alongside Alpine for Docker images unless there is a minimal resource version of Debian like the net-install, to help support a wider audience.

馃憤 1
ChillPillzKillzBillz14:10:02

Does anybody know how to update clojure installation to a newer version? I have clojure 1.11.1.1113 but for deps-new I need a higher version. Any help will be much appreciated!

Alex Miller (Clojure team)14:10:42

you can most likely just reinstall the latest version of whatever variant you have installed (not sure if you're using powershell, or deps.exe or something WSL2 based)

ChillPillzKillzBillz14:10:10

I've tried the power shell installation steps but nothing changes...

Alex Miller (Clojure team)14:10:19

I've had that happen before, trying to remember what I did

1
Alex Miller (Clojure team)14:10:48

you could try Import-Module -force path\to\ClojureTools.psm1

Alex Miller (Clojure team)14:10:18

not sure if you need to Uninstall-Module on the old one

ChillPillzKillzBillz14:10:04

ok. I got it. For anybody who wants to know... I went to the install location(in my case PowerShellModules\ClojureTools) and deleted the ClojureTools folder. Afterwards I just re-ran the installation steps. Et Viola! Shiny New Clojure awaits! Thanks @U064X3EF3 for indulging me in my pursuit!

mmer14:10:59

Does anyone know of a library that could add text to a PNG? Like adding a box with white background with text on that.

Nundrum14:10:56

Clojure2D can do that.

jpmonettas14:10:25

have you seen this https://blog.agical.se/en/posts/imagemagick--x--pango--x--babashka--x---x--x-/ @U0ETXRFEW has been lately publishing stuff around that kind of stuff

pez16:10:30

Assuming you are using regular JVM Clojure, I can recommend #membrane, Here鈥檚 a video I made yesterday about adding text to a PNG with Membrane, as it happens. 馃槂 https://www.youtube.com/watch?v=ImBji-1bKkc

pez16:10:58

That Youtube thumbnail is made with Membrane (and the video shows how). Here鈥檚 the starter project I created for it: https://github.com/PEZ/x-meta-image

Lukas Bloznelis15:10:09

Anyone using Conjure with nvim been able to disable default mappings? As per docs, I'm setting vim.g["conjure#mapping#enable_ft_mappings"] = false , but default mappings are still present.

Lukas Bloznelis15:10:35

return {
    "Olical/conjure",
    ft = { "clojure" }, -- etc
    -- [Optional] cmp-conjure for cmp
    dependencies = {
        {
            "PaterJason/cmp-conjure",
            config = function()
                local cmp = require("cmp")
                local config = cmp.get_config()
                table.insert(config.sources, {
                    name = "buffer",
                    option = {
                        sources = {
                            { name = "conjure" },
                        },
                    },
                })
                cmp.setup(config)
            end,
        },
    },
    config = function(_, opts)
        require("conjure.main").main()
        require("conjure.mapping")["on-filetype"]()
    end,
    init = function()
        vim.g["conjure#mapping#enable_ft_mappings"] = false
        vim.g["conjure#debug"] = true

        -- vim.g["conjure#mapping#eval_current_form"] = "ee"
        -- vim.g["conjure#mapping#eval_root_form"] = "er"
        -- vim.g["conjure#mapping#eval_comment_root_form"] = "e;"
        -- vim.g["conjure#mapping#eval_buf"] = "eb"
        -- vim.g["conjure#mapping#eval_visual"] = "E"
        -- vim.g["conjure#mapping#doc_word"] = ""
    end,
}
Entire config --^

practicalli-johnny16:10:03

This is how I simplified some of the UI aspects of Conjure for the AstroNvim Community Clojure pack (which is similar to the above). The config includes autocmd to set ;; as a comment and disable LSP diagnostics in the REPL log https://github.com/AstroNvim/astrocommunity/blob/main/lua/astrocommunity/pack/clojure/init.lua

seancorfield16:10:08

Answered in #CBE668G4R (please don't cross-post questions - be patient about getting an answer).

22:10:46

The Clojure website recommends using an LTS release of Java; however, I have spoken to people using 2X. So, I am confused about which version I should use.

mjhika22:10:38

https://www.oracle.com/java/technologies/java-se-support-roadmap.html looks like 21 is LTS. you should be okay using that. the asterisks in the graph suggest that dates and designations are subject to change.

mjhika22:10:05

i don't know that you will run into too many issues with the newest LTS. I have not messed with it too much. But generally the community will list any required deps if your version of java doesn't support a feature that the library relies on.

seancorfield22:10:40

@U05MPHVTGPK Clojure itself is tested against 8, 11, and 17 right now, both temurin and corretto JDKs, both with and without direct linking, e.g., https://github.com/clojure/clojure/actions/runs/6567873789 So those are what are "officially supported" (as far as a FOSS projects supports anything). That said, we've run a lot of stuff in production on JDK 18 & 20 (we hit a memory leak in 19 with --enable-preview) and we're testing against JDK 21 now (the new LTS release). One issue to be aware of with JDK 21 is if you build a (compiled) uberjar on 21, it may not run on 20 or earlier due to some changes in the class hierarchy introduced in 21 (`SequencedCollection`). As far as CI/QA/Production, we're waiting for our monitoring platform to support JDK 21 before we roll that out (New Relic).

practicalli-johnny23:10:32

Although Java 21 is the latest LTS release, I'll be staying on 17 for a little longer and conservatively updating to Java 21 by the end of the year. Unless a specific feature of Java 21 is needed, I'd stick with 17 for a little longer (unless you want to test things against Java 21) Its quite common to have several versions of Java installed and there are several tools to manage switching (if required)

Alex Miller (Clojure team)00:10:14

I did not immediately update the web site, because there was a delay in the release of Temurin 21, but that鈥檚 out there now so I will do that when I get a chance

00:10:46

Oh, I had no idea that 21 was the latest LTS. Granted, I was going off of the information on the website.

00:10:10

@U05254DQM I assume you mean asdf and the like for managing multiple versions of Java?

seancorfield01:10:20

@U05MPHVTGPK FWIW, I'm "old school" and use either JAVA_HOME or JAVA_CMD env vars to determine which JDK to use (Clojure CLI supports JAVA_CMD) and then I can override the defaults on a per invocation basis when testing.

seancorfield01:10:54

(/var/www/worldsingles)-(!2020)-> env|fgrep JAVA
JAVA_HOME=/Developer/jdk-21+35
JAVA_CMD=/Developer/jdk-21+35/bin/java

Thu Oct 19 18:24:08
(/var/www/worldsingles)-(!2021)-> env|fgrep OPENJDK
OPENJDK8_HOME=/Developer/jdk8u332-b09
OPENJDK20_HOME=/Developer/jdk-20.0.1+9
OPENJDK18_HOME=/Developer/jdk-18.0.2+9
OPENJDK19_HOME=/Developer/jdk-19.0.2+7
OPENJDK21_HOME=/Developer/jdk-21+35

seancorfield01:10:33

(and I set JAVA_HOME=$OPENJDK<n>_HOME and/or JAVA_CMD=$OPENJDK<n>_HOME/bin/java as needed)

seancorfield01:10:04

@U064X3EF3 Are you going to add temurin-21 to the test matrix for Clojure and all Contribs?

seancorfield01:10:55

Ah, Contrib is different to Clojure: https://github.com/clojure/build.ci/blob/master/.github/workflows/test.yml#L8-L11 -- so it's 8, 11, 17, with Clojure 1.9, 1.10, 1.11 by default... I need to learn how to override/extend that for my Contribs I guess...

Alex Miller (Clojure team)02:10:13

Just be patient, we鈥檒l get to it

seancorfield02:10:40

Ah, ok. That'll save me some work for now then:rolling_on_the_floor_laughing:

henrik06:10:40

We鈥檙e running 21, and it鈥檚 working well. We鈥檝e been introducing some virtual threads at the edges, in non-critical parts of the system to try them out.

henrik06:10:05

Corretto 21, for the record.

Mattias06:10:54

For an environment that is kept up to date with releases and patches, is there any upside to staying behind with LTS releases?

mbjarland09:10:44

FYI not sure if anybody would be interested but after dealing with multiple java version hell for years I wrote a babashka script a while back which supports tab completion switching of java versions installed with sdkman or with the os on bash/zsh linux/osx and supports rewriting (i.e. cleanly, not just appending) of PATH and JAVA_HOME. I could clean this up and create a github repo if anybody else would find this useful. I end up with something like this:

mbjarland09:10:53

Would probably be easy to mod to support other multi-install tools