Vagrantfile<3>--Configure GUI inside of VM for Mac

When using Vagrant for a project, we have two options.

  1. Using all development tools including IDE to edit code and compile in host, then run in VM.
      • better performance
      • synced_folder allows us to synchronize codes between VM and local.
      • hard to fix once mess up local development environment (like me !!!)
  2. Having another set of development tools in VM, developer writes code, compile and deploy in VM.
      • consistency: ensure the same development environment
      • lantency: GUI and Compiling. In SED, if I wanna use developer machine (like a high performance desktop), I have to ssh into server then vagrant ssh into VMs. We are now suffering high GUI latency when using IntelliJ in this situation (5 seconds for searching panel to show up). It is 2 X Forwarding, boss said it is an existing official bug.

In this blog, I will introduce these two methods.

IDE in host

This is achieved by a synced folder functionality of Vagrant. Introduced in Vagrantfile<2>–Vagrantfile
It synchronizes folder between VM and host.

Demo:

IDE in VM (Mac)

Relates keyword: DISPLAY, xhost, XForwarding, X Server, X Client

It is a little bit more complicated.
Basically, when running intelliJ, we should have a GUI window pop up. What we have to do now is to forward this window from VM to our host.

Some notations:

  • DISPLAY: an environment variable that indicates where to show this window.
    • Format: DISPLAY=IP:displaynumber.screennumber
    • e.g. DISPLAY=:0.0 show window in local
  • xhost: a list that is allowed to make connections to the X server
  • X Forwarding: Using X forwarding in an SSH session on your personal computer allows you to securely run graphical applications
  • X Server: e.g. host. It supplies screen for VM
  • X Client: e.g. VM. It uses the screen supplied by host.

Steps in theory

  1. Run a X Server in host (XQuartz for mac)
  2. Use X forwarding when ssh into VM
  3. Set proper DISPLAY in VM
  4. Run idea in VM

In Mac

  1. Install XQuartz, an Mac version of X Server.brew cask install xquartz
  2. Mac DISPLAY should already be set to DISPLAY=/private/tmp/com.apple.launchd.GxQDyjI1Mr/org.macosforge.xquartz:0
  3. vagrant ssh vm -- -X, -X relates to X forwarding.
  4. Run idea in VM

Common errors

  • Without X Server set.

    1
    2
    vagrant@ui:/synced_folder/idea-IC-183.4588.61/bin$ ./idea.sh
    Startup Error: Unable to detect graphics environment
  • Set DISPLAY in VM wihout X Server set.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    vagrant@ui:/synced_folder/idea-IC-183.4588.61/bin$ ./idea.sh

    Start Failed: Failed to initialize graphics environment

    java.awt.AWTError: Can't connect to X11 window server using ':0.0' as the value of the DISPLAY variable.
    at sun.awt.X11GraphicsEnvironment.initDisplay(Native Method)
    at sun.awt.X11GraphicsEnvironment.access$200(X11GraphicsEnvironment.java:65)
    at sun.awt.X11GraphicsEnvironment$1.run(X11GraphicsEnvironment.java:115)
    at java.security.AccessController.doPrivileged(Native Method)
    at sun.awt.X11GraphicsEnvironment.<clinit>(X11GraphicsEnvironment.java:74)
    at java.lang.Class.forName0(Native Method)
    at java.lang.Class.forName(Class.java:264)
    at java.awt.GraphicsEnvironment.createGE(GraphicsEnvironment.java:103)
    at java.awt.GraphicsEnvironment.getLocalGraphicsEnvironment(GraphicsEnvironment.java:82)
    at sun.awt.X11.XToolkit.<clinit>(XToolkit.java:128)
    at java.lang.Class.forName0(Native Method)
    at java.lang.Class.forName(Class.java:264)
    at java.awt.Toolkit$2.run(Toolkit.java:860)
    at java.awt.Toolkit$2.run(Toolkit.java:855)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.awt.Toolkit.getDefaultToolkit(Toolkit.java:854)
    at com.intellij.ui.AppUIUtil.updateFrameClass(AppUIUtil.java:161)
    at com.intellij.idea.StartupUtil.prepareAndStart(StartupUtil.java:94)
    at com.intellij.idea.MainImpl.start(MainImpl.java:20)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at com.intellij.ide.plugins.PluginManager.lambda$start$0(PluginManager.java:75)
    at java.lang.Thread.run(Thread.java:745)

reference