Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Shell into a Docker container running on a Heroku dyno. How?

Tags:

docker

heroku

Given a dyno in which a container is running, what's the Heroku equivalent of docker exec -it blarg /bin/bash? That is, how can one open a shell into the already-running container?

Example Dockerfile:

FROM heroku/heroku:16
CMD while true; do sleep 1; done

Example run:

$ heroku container:push my_app
<wait a minute>
$ heroku ps
=== my_app (Free): /bin/sh -c while\ true\;\ do\ sleep\ 1\;\ done (1) 
my_app.1: up 2017/10/09 12:13:07 -0600 (~ 4m ago)

So far so good.

But now...

$ heroku ps:exec --dyno=my_app.1
Establishing credentials... error
 ▸    Could not connect to dyno!
 ▸    Check if the dyno is running with `heroku ps'

For good measure I check heroku ps at this point and it shows that the dyno is still running.

Yes, I've done all the things Heroku suggests to enable Docker support. Per the documentation, I have tried using a base image of my choice while ensuring that bash, curl, openssh, and python are present. I have also tried using the Heroku-16 base image, as shown in the above example.

(The linked documentation also references steps required for Private Spaces. Since I'm not using Private Spaces I have not applied those steps.)

like image 923
kkurian Avatar asked Oct 09 '17 18:10

kkurian


People also ask

How do I run a Docker container on Heroku?

Heroku provides two ways for you to deploy your app with Docker: Container Registry allows you to deploy pre-built Docker images to Heroku. Build your Docker images with heroku. yml for deployment to Heroku.

Can I SSH into Heroku dyno?

Heroku Exec allows you to create an SSH-based terminal session into a dyno. You can also use Exec to connect remote debuggers, and other tools that require an SSH tunnel, to a dyno.

Can I SSH Heroku?

Heroku Exec is a feature for creating secure TCP and SSH tunnels into a dyno. It allows for SSH sessions, port forwarding, remote debugging, and inspection with popular Java diagnostic tools.


5 Answers

EDIT CIRCA 2022 This was the accepted answer in 2017. I'm not so sure anymore, so I'm unaccepting my answer here to avoid misleading anyone. I'm not fiddling with Heroku + Docker these days, so I'm not in a good position to accept an answer.

TL;DR Ensure that bash is installed in the image and add this to your Dockerfile:

RUN rm /bin/sh && ln -s /bin/bash /bin/sh

Explanation

Contrary to what the documentation would lead one to believe, Heroku does not, out of the box, support heroku ps:exec into a Docker container already running in a dyno.

Quoting from responses I have received from the Heroku team:

Our ps:exec feature ... works ... by injecting a bash file into dynos, opening an additional port in the background, and allowing you to connect to it.

[T]he default shell used by Docker is /bin/sh, which is not compatible with the Heroku Exec script (it's requires /bin/bash).

There is a workaround you can use though. Put the following in your Dockerfile:

RUN rm /bin/sh && ln -s /bin/bash /bin/sh

This is definitely a gap in our product, and we'll work to make this better.

like image 191
kkurian Avatar answered Oct 19 '22 20:10

kkurian


If bash is installed, run heroku run bash. This will get you into the shell from your command line.

You can also use the GUI and go to "More" -> "Run Console" on your heroku app, and input "bash" to bring it up there.

like image 7
Jay Jung Avatar answered Oct 19 '22 19:10

Jay Jung


Edited: In order to run heroku ps:exec on apps with Docker and deployed via the Container Registry you have to enable runtime-heroku-exec. You can do heroku features:enable runtime-heroku-exec to enable it

Here you can see the documentation of exec with the instructions to enable docker support

like image 3
nicolastrres Avatar answered Oct 19 '22 19:10

nicolastrres


in my situation, to get this working with Ubuntu 20.04 (focal), i had to additionally install the python-is-python3 package into the docker image, to get heroku-exec working.


here is a working example (october 2020) of an ubuntu-based dockerfile, that works with heroku-exec:

FROM ubuntu:focal

# install required packages
RUN export DEBIAN_FRONTEND=noninteractive && apt-get update && apt-get install -y python3 curl python-is-python3 openssh-server iproute2 nginx && apt-get clean

# simplfy nginx config to enable ENV variable substitution
RUN echo 'server { listen PORT_NUMBER; }' > /etc/nginx/sites-enabled/default

# add config required for HEROKU_EXEC
# ENV HEROKU_EXEC_DEBUG=1
RUN rm /bin/sh \
 && ln -s /bin/bash /bin/sh \
 && mkdir -p /app/.profile.d/ \
 && printf '#!/usr/bin/env bash\n\nset +o posix\n\n[ -z "$SSH_CLIENT" ] && source <(curl --fail --retry 7 -sSL "$HEROKU_EXEC_URL")\n' > /app/.profile.d/heroku-exec.sh \
 && chmod +x /app/.profile.d/heroku-exec.sh

# configure NGINX to listen on dynamic $PORT env variable supplied by Heroku.
CMD sed -i 's/PORT_NUMBER/'"$PORT"'/g' /etc/nginx/sites-enabled/default; nginx -g 'daemon off;'

then connect with this command:

heroku ps:exec -a name-of-app-12345
like image 2
DrGecko Avatar answered Oct 19 '22 19:10

DrGecko


Both heroku run /bin/bash and heroku ps:exec won't work in my situation. The former opens a new container which is different from the real one running! The latter just doesn't work in my container of alpine3, though heroku features:enable runtime-heroku-exec can succeed. My solution is to bring up a shell server and a traffic forwarder in the container. Then on the client connect to the shell server with tunnel created by traffic forwarder.

traffic flow:

localhost:2023 -> chisel client -> ...tunnel... -> chisel server -> localhost:8182

In conainer, start up a shell server with socat and a tunnel server with chisel:

nohup socat tcp-l:8182,reuseaddr,fork exec:/bin/bash,pty,setsid,setpgid,stderr,ctty > /tmp/socat.log 2>&1 &

nohup ./chisel server --port $PORT --proxy http://httpbin.org > /tmp/chisel.log 2>&1 &

On client side, start a chisel client to forward traffic from localhost:8182 to the socat on the server

chisel client http://yourapp.herokuapp.com/  0.0.0.0:2023:localhost:8182

on client side, open another terminal window:

socat -,raw,echo=0 tcp:127.0.0.1:2023

How to get the chisel on server? Download it or just compile from source in Dockerfile

download chisel

like image 1
Iceberg Avatar answered Oct 19 '22 21:10

Iceberg