basecamp / kamal

Deploy web apps anywhere.
https://kamal-deploy.org
MIT License
11.35k stars 450 forks source link

Skip building an deploy some public docker image (listed at Docker Hub) #497

Open meglio opened 1 year ago

meglio commented 1 year ago

I could not find where the documentation explains how to make Kamal skip the "build" step and just deploy some docker image found at the public Docker Hub.

image

meglio commented 1 year ago

I think I found it in the Config section:

image
meglio commented 1 year ago

Still, it is looking for some Dockerfile. Can it do without it and just use the public docker image?

image
danthrue commented 1 year ago

Try to use the --skip-push option, seems to be doing what you are searching for.

Edit: I've done some further testing today, it seems --skip-push only works for the deploy and redeploy commands. The setup ends calling the deploy command and it doesn't support that...

akoskovacs commented 10 months ago

This would be really helpful even when you already have a built private image (from the same ghcr.io registry that you use in deploy.yml).

I would image the deploy.yml having something like this as an option:

builder:
  disable: true
n1xn commented 10 months ago

I'm in the same boat and also need to skip the builder step. As my workflow requires to run rails tests and linters successfully before pushing it to ghcr registry. With the current solution I would build the image twice.

on:
  push:
    branches: [ main ]

jobs:
  build-test-push:
    runs-on: ubuntu-latest

    permissions:
      contents: read
      packages: write

    steps:
      - name: check out repository
        uses: actions/checkout@v4

      - name: set up docker buildx
        uses: docker/setup-buildx-action@v3

      - name: build & cache Docker image
        uses: docker/build-push-action@v5
        with:
          load: true
          tags: ${{ github.repository }}:${{ github.sha }}
          cache-from: type=gha
          cache-to: type=gha,mode=max

      - name: run Rails tests & linter
        run: docker-compose -f docker-compose.ci.yml up --abort-on-container-exit

      - name: log in to GitHub Container Registry
        uses: docker/login-action@v3
        with:
          registry: ghcr.io
          username: ${{ github.actor }}
          password: ${{ github.token }}

      - name: push Docker image to GitHub Container Registry
        uses: docker/build-push-action@v5
        with:
          push: true
          tags: ghcr.io/${{ github.repository }}:${{ github.sha }}

  #__DEPLOY
Intrepidd commented 10 months ago

I'm also trying to deploy a public image with kamal and encounter some of the same issues.

Even with kamal deploy -P, kamal will try to get an image that has been tagged with the current commit sha. Even with kamal deploy -P --version=v0.48.1, kamal will fail because the image does not have the service label

I think I'll have to create a one-line Dockerfile that is just a FROM some/publicimage to bypass this but it would be so so great to be able to easily release any public docker image with kamal

flozano commented 9 months ago

I am evaluating kamal for my use-case but I'm having the same problem. My build process generates an image already, I just want to release it. Making the build process optional for the entire workflow would be great.

spryffee commented 9 months ago

Same issue for me. Not having the ability to skip build step makes Kamal nearly useless for public images

RyanMcCoskrie commented 9 months ago

This is a feature Kamal is desperately missing.

I have made an open source rails app and have been trying to figure out how to best simplify deployment for other people. At present using DockerHub + Kamal would require sharing my password with the entire world.

Please add a no-login option.

sulo1337 commented 8 months ago

What I'm doing currently is creating a dummy busybox container for a placeholder in the service so I can deploy public docker images as an accessory.

Dockerfile example:

FROM busybox:1.36.1

CMD ["tail", "-f", "/dev/null"]

kamal-config example:

# Name of your application. Used to uniquely configure containers.
service: kamal-test

# Name of the container image.
image: <registry-username>/kamal-test

servers:
  - 1.1.1.1

registry:
  username: <registry-username>
  password:
    - KAMAL_REGISTRY_PASSWORD

ssh:
  user: <ssh-user>

accessories:
  app:
    image: nginx:1.24.0
    host: 1.1.1.1
    port: 127.0.0.1:8080:80
    files:
      - nginx.conf:/etc/nginx/nginx.conf

# Since the dummy service is not serving anything, healthcheck is set to true.
# probably there are other ways to optimize this to get true healthcheck (proxying healthcheck to "app" accessory)
healthcheck:
  cmd: /bin/true
benbonnet commented 8 months ago

Kamal is a wonderful tool, too bad it does not provide this capacity yet

While using --skip-push, a very minimal change here would make it all work.

It could just accepts something from the cli (like --tagged-image xyz:latest) and skip the build

acidtib commented 8 months ago

Kamal is a wonderful tool, too bad it does not provide this capacity yet

While using --skip-push, a very minimal change here would make it all work.

It could just accepts something from the cli (like --tagged-image xyz:latest) and skip the build

please make a pull request!

benbonnet commented 8 months ago

@acidtib I did a very simple hack in a fork here. Passing a new arg would require awkward changes, so either ENV["TAGGED_IMAGE"] or static tagged_image key at the top level. Still coupled with --skip-push

To be honest, by looking at the code, the "deploy local code only" is deeply rooted. Coupled with the fact that each elements in the servers: block use the same image

IMHO a good refactor would be to prioritize the requirement discussed in this issue (which would make the concept of accessories pointless somehow), and falling back to the current existing behaviour (local code build/push)

A possibility would be to allow primary_role to accept an accessory, but then servers could be empty.

Anyways, those are personal thought; there might be other ways. But overall it feels like things were heavily focused on building your current code, nothing else

joelcogen commented 6 months ago

Seems like you can achieve this with the VERSION env var combined with -P. This is the command I use to deploy the latest image (already built for staging) to production:

VERSION=latest kamal deploy -P -d production
djmb commented 6 months ago

Kamal requires that images are labeled with the service, so that it can identify them when pruning.

So right now you can't deploy arbitrary public images. If you have an external image that you've built yourself with the service label, then you can either also tag it with the appropriate git SHA or use @joelcogen's suggestion to override the version.

gregjotau commented 4 months ago

Seems like you can achieve this with the VERSION env var combined with -P. This is the command I use to deploy the latest image (already built for staging) to production:

VERSION=latest kamal deploy -P -d production

Did you get this to work to deploy the latest image.

I am doing:

./gradlew bootBuildImage && VERSION=latest; kamal deploy -P

but getting:

docker stderr: Error response from daemon: manifest for XX/YY:a4da0e855e22e06611c6b4a1ea5f76ebdec20411_uncommitted_419e2abc190b3302 not found: manifest unknown: manifest unknown

The docker image built with bootBuildImage pushed to docker hub is 191 MB Vs. 291 MB that Kamal builds with Docker "out of the box", so it would be good to be able to simply deploy the latest image.

djmb commented 4 months ago

@gregjotau - does it work if you remove the ; after VERSION=latest?

gregjotau commented 4 months ago

@gregjotau - does it work if you remove the ; after VERSION=latest?

Thanks for the quick response!

Then I get: docker stdout: Image XX/YY:latest is missing the 'service' label docker stderr: Nothing written

djmb commented 4 months ago

That's a requirement of Kamal, you'll need to add a label called "service" to your image. The value should be the same as the service in your Kamal configuration.

gregjotau commented 4 months ago

That's a requirement of Kamal, you'll need to add a label called "service" to your image. The value should be the same as the service in your Kamal configuration.

Yep, figured it out and worked when adding: environment.set(mapOf("BP_IMAGE_LABELS" to "service=\"XX\"")) in config

Thanks!

JUVOJustin commented 3 weeks ago

Was anybody able to make this work with kamal2? Tried adding the label, and deploying with kamal deploy -P.

Part of my deploy.yml:

service: gotenberg

image: gotenberg/gotenberg:8

labels:
  service: gotenberg

Kamal still tries to log in to the registry every time.

denisorehovsky commented 2 weeks ago

This still hasn’t been fixed after a year? I build an image using GitHub Actions and then push it to GitHub’s registry. I don’t want Kamal to build anything. It’s strange that I can’t skip this step.

jdelStrother commented 1 week ago

Seems like you can achieve this with the VERSION env var combined with -P. This is the command I use to deploy the latest image (already built for staging) to production:

VERSION=latest kamal deploy -P -d production

@joelcogen Thanks, this was useful. I've been trying for ages to build an image in Github Actions and then deploy it from my Macbook without having to rebuild it locally. I ended up with VERSION=$(git rev-parse HEAD) kamal deploy -P.

isteel commented 1 week ago

Proving impossible to deploy pihole/pihole image to a local Pi using kamal2. From reading these posts it seems that I need to build my own image of pihole, label it to match the service, push it back to dockerhub and then deploy. But the issue then is that the sha1 from my local git repository (which I had to create as kamal2 insists on using git to determine the latest version) doesn't match the tag on dockerhub.

Am I going down the completely wrong rabbit hole with this? It doesn't feel natural.

djmb commented 1 week ago

It's a hard requirement of Kamal right now that images have the service label, so we can identify them when pruning.

We could switch that to filtering by reference instead and drop the requirement, then we could deploy any image which would definitely be nice to be able to do.

Not completely straightforward though. If someone is deploying multiple apps to a server using the same image, we'd need to make sure app A doesn't try to prune images used by app B.