Using Docker with CLion

One of the common questions we get is why there is no Docker integration in CLion? In fact CLion works very nicely with Docker! There might not (yet) be a specific, “use Docker”, button – but setting it up yourself is actually quite easy and straightforward – even if you’re a Docker newbie!

Read on if you prefer written instructions, or watch this video with the same content:

  1. Why use Docker?
  2. Getting Docker
  3. Creating a Docker container for use with CLion.
  4. Using the Remote Development workflow with Docker
  5. Changing the Docker environment
  6. Good luck getting Dockerized!

Why use Docker?

But why would you want to do this at all? Docker is not just the latest trend, but it represents a new way of setting up different environments in a quick, easy, reproducible and reliable way – that is easy to share, say, in version control.

Common uses for C++ developers are: working with multiple toolchains (especially different versions of the same compiler – which can be very tricky to maintain otherwise), working with cross-compilers for different platforms, or even just using a single environment but making it easy for everyone on your team to get the same environment quickly and easily (and keep it updated).

Docker is lighter-weight than a VM, but gives you essentially the same levels of isolation. It sounds complex to set-up, but one of the surprises for many is just how easy it is to get going.

Getting Docker

If you don’t already have it you’ll need to install the Docker Engine. This is fairly straightforward, although there may be a few extra steps, depending on your platform. The docs are excellent throughout, and the installation instructions are no exception – so check them out for your platform.

Creating a Docker container for use with CLion.

Docker containers are described in Dockerfiles. These look like simple scripts, but have a few special properties that make them a bit special.

First, you can refer to a “base image”, which is a prebuilt container, usually available via a docker registry, which does a lot of the heavy lifting. We’ll use a Ubuntu base image to give us a common platform to start with – but other OS images are available. E.g.

Secondly, each line in a Dockerfile is executed on what Docker calls a layer. Each layer is immutable, once created – so any mutations on the layer above can be easily, and cheaply, rolled back – without having to recreate all the layers beneath.

That’s one of the things that makes Docker such a fast and productive environment once you get used to it. We won’t go into this in any more depth, here. It’s worth going through the introductory docs if you want to get more of a feel for it.

We’ve created a reference Dockerfile for you to get started. It should be fairly obvious how to change this to meet your needs.

Mostly you’ll change the apt-get part, which should be immediately familiar if you’ve used Ubuntu, before. Of course if you change the base image you may need to use a different approach to getting dependencies there. The point is it is just using the base image OS’s package manager (within Docker’s RUN command).

You may also be able to get (or create yourself) a base image with all the dependencies already set up.

The Dockerfile then sets up SSH, so CLion can connect into it, and creates a user for CLion to use.

Usually the credentials needn’t be too obscure, but of course you can change them if you need to – or use another way (beyond the scope of this intro) to specify the details without mentioning them in the Dockerfile.

At the top of the Dockerfile, in the comments, are the three commands you’ll need to execute to build and run this Docker container.

The first builds the container:

This will take a few minutes to run, as it downloads the Ubuntu image (whether or not you are already running on Ubuntu), “installing” that into the first layer, installing all the dependencies (that apt-get line), setting up SSH and creating the user! Given all that it is surprisingly fast (and you should only have to do this once).

Once built you can run the container, using the next line:

The -d runs the container as a daemon, so control returns back to you.
--cap-add sys_ptrace adds the ptrace capability, which is necessary for debugging. Docker containers are usually very minimal, by default, so you sometimes need to enable fundamental things.

-p2222:22 specifies a port mapping. Port 22 (the default SSH port) inside the container is mapped to outside the container as port 2222 on the host environment.

There’s nothing special about 2222. Doubling up, or multiplying by 10 are common ways of expressing mapped ports, but you could specify any available port number, here. That can be useful if you intend to run multiple containers side-by-side (e.g. to support alternate toolchains).

Whatever port number you chose, since it’s only temporarily mapped, and may be reused, it’s usually worth clearing any cached SSH keys:

Don’t worry if that tells you it couldn’t find any – likely the first time.

So now the Docker container is up and running, ready with your toolchain installed. All that’s left is to get CLion to use it.

Using the Remote Development workflow with Docker

Since we set-up SSH in our container we can connect into it using CLion’s standard Remote Development features. See our help pages for full details on setting up Full Remote Mode.

In short, you should add a new Toolchain entry in settings under Build, Execution, Deployment as a Remote Host type.

Then click on the in the Credentials section and fill out the SSH credentials we set-up in the Dockerfile (Host: localhost, Port: 2222, User name: user, Password: password).

Finally, add a CMake profile that uses this toolchain and you’re done. If you want more fine grained control over the paths used inside the container take a look at the Deployment settings page.

Either way, once you commit (Apply and/ or OK) out of settings, and wait for the CMake profile to load, and files to transfer, you can then select the CMake profile from the Run Config drop-down, and your code will now be compiled, run and debugged, within the container using the specified toolchain.

If the container has an earlier version of CMake than your local project (and you created the project, first, locally) then you may need to set the CMake version back at the top of the CMakeLists.txt file.

You could also get a later version of CMake in the Dockerfile but that’s beyond the scope of this post.

Changing the Docker environment

If you need to make changes to the container you may need to re-run the build step, as well. Consult the Docker docs to be sure, as it’s not always obvious whether a change has taken effect, due to Docker’s extensive caching (usually a good thing).

If you do rebuild you’ll probably also have to reload the CMake project, as well.

Good luck getting Dockerized!

That should be all you need to get started. Be sure to read the Docker docs to get the most out of Docker, itself. And check out the Remote Development docs in the CLion help for a few more details that may be helpful, too.

About Phil Nash

Developer Advocate at JetBrains for CLion, AppCode and ReSharper C++
This entry was posted in Tips'n'Tricks and tagged , , . Bookmark the permalink.

16 Responses to Using Docker with CLion

  1. Johnathan Raymond says:

    Probably shouldn’t expose the ssh port you create to the world – not a big deal, but:


    docker run -d --cap-add sys_ptrace -p”127.0.0.1:2222:22” --name clion_remote_env clion/remote-cpp-env:0.5

  2. Eric Pederson says:

    Does this work like the WSL2 integration? It seems like you should be able to take advantage of bind mounts to avoid transferring files (especially on Windows CLion).

    • Phil Nash says:

      Eric (and Alexey, who asks essentially the same question): we don’t, currently, support mounted volumes in this way – but appreciate that it would be useful. We are looking at adding it to an upcoming release, but I can’t give you specifics just yet.

      • Alexey says:

        I’ve just changed the flavour of deployment from ‘SFTP’ to ‘local or mounted folder’. And then pointed to the parent folder relative to project root folder.

        In ‘mapping’ I’ve set local path (absolute path to project root) and ‘deployment path’ (just project root).

        In cmake I usually have build folder relative to parent of project root (i.e. something like ../project-build/Debug).

        With all this in mind I can run ‘reload’ and ‘rebuild’.
        Both works well, project can be built and I can run debug.
        In all these actions NO active file transfers noticed, i.e. clion works as expected and doesn’t upload/download anything.

        So, what do you men by ‘we don’t currently support it’? That it has to be set up manually?
        Well, that is not the big deal (especially taking in mind that it is usually onetime action, and you don’t need to run it again and again on every build).

        Then I’ve noticed that all now works without transferring

        • Phil Nash says:

          Nice and creative :-)
          Glad you got it to work – and anyone reading this can certainly try the above at their own risk – this is not “officially” supported, and has some issues. Apparently this will break after every CLion restart – and may be unpredictable in other ways.

          As I say, we aim to have a properly supported method in the near future, but probably not the next release.

        • Eric Pederson says:

          Hi Alexey –

          Which host OS are you using? I tried this approach with a Windows 10 host and got close but not quite. CLion loads the CMakeLists.txt and generates the build system in the container, but none of the build targets show up in the Run Configuration menu.

      • Eric Pederson says:

        Good to hear!

        Here’s a recent blog post from Docker that is related: https://www.docker.com/blog/deep-dive-into-new-docker-desktop-filesharing-implementation

  3. Alexey says:

    1. On installing build-essential you don’t need to install gcc and g++, they’re redundant.

    2. Dockerized build often used for build not only cross-platform, but kind of ancient systems where cmake may be either not shipped, either ancient. So, it is reasonable to directly install fresh one from tarball as separate layer. For example, by ADD cmake-3.14.0-Linux-x86_64.tar.gz / command. Then you need either create .bashrc in the docker and add ‘export PATH….’ with path to cmake, either just write this path when set up toolchain in clion – to find this fresh cmake.

    3. On another flavours (say, centos 6 or centos 7) you also need to run ssh-keygen at the end of ssh install chunk of the script. Otherwise docker will not have host key, and it is not immediately obvious how to fix it. Piece looks like useradd -m user \
    && yes password | passwd user \
    && ssh-keygen -f /etc/ssh/ssh_host_ecdsa_key -N '' -t ecdsa -b 521 \
    && ssh-keygen -f /etc/ssh/ssh_host_rsa_key -N '' -t rsa \
    && ssh-keygen -f /etc/ssh/ssh_host_dsa_key -N '' -t dsa

    4. It is extremely useful to set also mounted volume when running docker (with -v option) to make your sources available directly from the host. And then when setting up toolchain – set deployment method to ‘local or mounted folder’. That will make debugging and developing much more transparent, and also save for you time and disk space.

    • Phil Nash says:

      Thanks Alexey. See response to Eric regarding (4). For (2) and (3) that’s valuable additional information – thanks.
      For (1), that’s also useful to know. Maybe we’ll update the Dockerfiles. On the other hand it can be useful, for the sake of the reference example, to show the tool being explicitly mentioned. Either way, thanks for your input.

  4. Well, using SSH with docker and letting the container running all the time in detached mode is a way to work around the docker support.

    But this is not the way how docker normally works. normally there is no ssh running in the container, and interaction with the container happens with docker copy and the docker only runs as long as there is a task to do eg compile, generate CMake or debug. run the application.

    I would like to know is there a plan to make more native docker support rather than a workaround with the remote development over ssh.

  5. Ernest says:

    That would be very useful only if the remote development would work. Foreseeing the next comment with “Remote dev works in CLion”, no it isnt, when syncing any decent project takes 4 hours I call it broken.

    • Anastasia Kazakova says:

      We would be happy to investigate what’s going on there for you. Could you please create a ticket in YouTrack and attach an IDE log to start with?

  6. Niklas says:

    When proper Docker support is available, will it just work with Conan?

Leave a Reply

Your email address will not be published. Required fields are marked *