DEV Community

Jesse Wei
Jesse Wei

Posted on

Run A Python GUI App in Docker

Running a Python GUI app built with tkinter in Docker containers can be tricky. Tkinter cannot access the X11 socket, which it relies on to display graphical interfaces, of the Docker host from a Docker container without proper configuration. In this post, I want to share my hack for making my tkinter app work in Docker on a Mac machine.

Table of Contents

Development Environment

  • macOS Monterey 12.6
  • docker 20.10.17
  • docker-compose 1.29.2

Step 1: Prepare Directories & Files

Create a directory for our project and within it, create a Dockerfile, a docker-compose.yml file and a src/ directory. Your directory tree should look like this.

├── Dockerfile
├── docker-compose.yml
└── src
    └── app.py
Enter fullscreen mode Exit fullscreen mode

Step 2: Add Some Code

Copy & paste the following code into your Dockerfile.

FROM python:3.10.7

WORKDIR /usr/src/app

COPY . .

CMD [ "python3", "./app.py" ]
Enter fullscreen mode Exit fullscreen mode

Create an .env file at the root of the project and add the following code to it.

SRC_PATH=./src
Enter fullscreen mode Exit fullscreen mode

Then copy & paste the following code into your docker-compose.yml file.

version: '3'
services:
  python3:
    build: .
    container_name: 'python3'
    stdin_open: true
    working_dir: '/usr/src/app'
    tty: true
    volumes:
      - ${SRC_PATH}:/usr/src/app
    environment:
      - DISPLAY=YOUR_IP_ADDRESS:0.0
Enter fullscreen mode Exit fullscreen mode

Note: we have a DISPLAY environment variable set to YOUR_IP_ADDRESS:0.0 for now, which we'll replace with our real ip address later.

Then, copy & paste the following code into your src/app.py file.

from tkinter import *
from tkinter import ttk

root = Tk()

frm = ttk.Frame(root, padding=10)
frm.grid()

ttk.Label(frm, text="Hello World!").grid(column=0, row=0)
ttk.Button(frm, text="Quit", command=root.destroy).grid(column=1, row=0)

root.mainloop()
Enter fullscreen mode Exit fullscreen mode

Step 3: Install & Configure XQuartz

XQuartz is needed for our app to work in Docker on a Mac machine. So go to https://www.xquartz.org/, download and install it.

XQuartz

After installation, open Preferences > Security and make sure both boxes are checked. Then restart XQuartz.

Step 4: Find Our IP Address

Remember in step 2, we had the DISPLAY environment variable set to a placeholder. Now we need to replace it with our real ip address.

Open System Preferences > Network. You can find your ip address here.

find ip address

Replace the OUR_IP_ADDRESS part in docker-compose.yml with the ip address above. (e.g. if your ip address is 100.1.00.11, the DISPLAY environment variable value should be 100.1.00.11:0.0).

Step 5: Build Image & Run Container

Before we can build our image and run our container, we need to run the following command in shell to disable X server's access control so that our app can access the host's X11 socket from within the container.

xhost +
Enter fullscreen mode Exit fullscreen mode

Finally, let's build our image and run our container.

docker-compose up -d --build
Enter fullscreen mode Exit fullscreen mode

The tkinter app window should pop up like the following.

tkinter window

Conclusion

When trying to run tkinter apps in Docker on a Mac, you may get various errors like _tkinter.TclError: no display name and no $DISPLAY environment variable or _tkinter.TclError: couldn't connect to display ~. These are due to incorrect configuration of the DISPLAY environment variable or the X window system.

I found a lot of proposed solutions online but none of them worked for me. I tested multiple tricks and finally managed to get it work so if you were like me, this article may help you out.

Top comments (0)