NixOS / nixpkgs

Nix Packages collection & NixOS
MIT License
17.3k stars 13.54k forks source link

Chromium in container `Fontconfig error: Cannot load default config file: No such file: (null)` #176081

Open yajo opened 2 years ago

yajo commented 2 years ago

Describe the bug

It seems to be a resurrection of https://github.com/NixOS/nixpkgs/issues/101211, or at least I found proper STR.

When Chromium is executed inside a container, it cannot find fontconfig and it fails.

Steps To Reproduce

Steps to reproduce the behavior:

  1. Add this flake.nix:
    {
      inputs.nixpkgs.url = "nixpkgs/f1c9c23aad972787f00f175651e4cb0d7c7fd5ea";
      outputs = {
        self,
        nixpkgs,
      }: let
        pkgs = nixpkgs.legacyPackages.x86_64-linux;
      in {
        packages.x86_64-linux.default = pkgs.dockerTools.streamLayeredImage {
          name = "chromium";
          tag = "latest";
          config = {
            Cmd = [
              "${pkgs.chromium}/bin/chromium"
              "--headless"
              "--no-default-browser-check"
              "--no-first-run"
              "--disable-extensions"
              "--disable-background-networking"
              "--disable-background-timer-throttling"
              "--disable-backgrounding-occluded-windows"
              "--disable-renderer-backgrounding"
              "--disable-breakpad"
              "--disable-client-side-phishing-detection"
              "--disable-crash-reporter"
              "--disable-default-apps"
              "--disable-dev-shm-usage"
              "--disable-device-discovery-notifications"
              "--disable-namespace-sandbox"
              "--user-data-dir=/tmp/chrome-data-dir"
              "--disable-translate"
              "--autoplay-policy=no-user-gesture-required"
              "--window-size=1366x768"
              "--remote-debugging-address=127.0.0.1"
              "--remote-debugging-port=0"
              "--no-sandbox"
              "--disable-gpu"
            ];
          };
        };
        devShells.x86_64-linux.default = pkgs.mkShell {
          buildInputs = [pkgs.podman];
        };
      };
    }
  2. Run these commands:
    nix develop # to enter the shell with podman
    nix build
    ./result | podman load
    podman run --rm -it --mount type=tmpfs,tmpfs-size=512M,destination=/tmp localhost/chromium:latest

Expected behavior

Chromium shouldn't fail with the fontconfig error.

Screenshots

N/A

Additional context

I'm packaging Odoo in a container. It uses Chromium behind the scenes to run unit tests. I included all the flags it uses (resolved) to run Chromium in a container-friendly fashion.

Tests fail with Inspector.targetCrashed error.

A similar container-based approach based on debian doesn't crash like this. I inspected the same command in both containers and found that this issue's error is the main difference.

When I run the same command outside the container, Chromium works happily. My guess is that it's getting the font config from my host OS (Fedora Silverblue 36). I'm not using NixOS FWIW.

Notify maintainers

@primeos @thefloweringash

Metadata

I gave a nix flake to get it more reproducible, so I guess this is the required metadata:

[user@system:~]$ nix --version
nix (Nix) 2.8.0
yajo commented 2 years ago

The problem goes away with this patch:

           "--no-sandbox"
           "--disable-gpu"
         ];
+        Env = [
+          "FONTCONFIG_FILE=${pkgs.fontconfig.out}/etc/fonts/fonts.conf"
+          "FONTCONFIG_PATH=${pkgs.fontconfig.out}/etc/fonts/"
+        ];
       };
     };
     devShells.x86_64-linux.default = pkgs.mkShell {

I'm not sure if this is expected behaviour. It was surprising to me TBH.

jtojnar commented 2 years ago

I would say that is expected. Fontconfig requires /etc/fonts/fonts.conf to exist so if you want to run GUI apps in a container, you will need to create the file or use the environment variable workaround.

Though I guess it might make sense to patch fontconfig as follows to allow it working in environments where fontconfig is not installed globally:

--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -80,6 +80,7 @@ AM_CPPFLAGS =                         \
    $(WARN_CFLAGS)                  \
    -DFC_CACHEDIR='"$(FC_CACHEDIR)"'                \
    -DCONFIGDIR='"$(CONFIGDIR)"'            \
+   -DFALLBACK_FONTCONFIG_PATH='"$(prefix)/etc/fonts"'\
    -DFONTCONFIG_PATH='"$(BASECONFIGDIR)"'      \
    -DFC_TEMPLATEDIR='"$(TEMPLATEDIR)"'
 LDADD  = $(LIBINTL)
--- a/src/fccfg.c
+++ b/src/fccfg.c
@@ -2439,7 +2439,7 @@ FcConfigGetPath (void)
     int        npath;
     int        i;

-    npath = 2; /* default dir + null */
+    npath = 3; /* default dir + fallback dir + null */
     env = (FcChar8 *) getenv ("FONTCONFIG_PATH");
     if (env)
     {
@@ -2491,6 +2491,14 @@ FcConfigGetPath (void)
     if (!path[i])
    goto bail1;
     strcpy ((char *) path[i], (const char *) dir);
+
+    // Fallback for Nixpkgs.
+    dir = (FcChar8 *) FALLBACK_FONTCONFIG_PATH;
+    path[i] = malloc (strlen ((char *) dir) + 1);
+    if (!path[i])
+        goto bail1;
+    strcpy ((char *) path[i], (const char *) dir);
+
     return path;

 bail1:
nixos-discourse commented 2 years ago

This issue has been mentioned on NixOS Discourse. There might be relevant details there:

https://discourse.nixos.org/t/imagemagicks-convert-command-fails-due-to-fontconfig-error/20518/3

kfiz commented 1 year ago

I would say that is expected. Fontconfig requires /etc/fonts/fonts.conf to exist so if you want to run GUI apps in a container, you will need to create the file or use the environment variable workaround.

Though I guess it might make sense to patch fontconfig as follows to allow it working in environments where fontconfig is not installed globally:

--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -80,6 +80,7 @@ AM_CPPFLAGS =                       \
  $(WARN_CFLAGS)                  \
  -DFC_CACHEDIR='"$(FC_CACHEDIR)"'                \
  -DCONFIGDIR='"$(CONFIGDIR)"'            \
+ -DFALLBACK_FONTCONFIG_PATH='"$(prefix)/etc/fonts"'\
  -DFONTCONFIG_PATH='"$(BASECONFIGDIR)"'      \
  -DFC_TEMPLATEDIR='"$(TEMPLATEDIR)"'
 LDADD  = $(LIBINTL)
--- a/src/fccfg.c
+++ b/src/fccfg.c
@@ -2439,7 +2439,7 @@ FcConfigGetPath (void)
     int      npath;
     int      i;

-    npath = 2;   /* default dir + null */
+    npath = 3;   /* default dir + fallback dir + null */
     env = (FcChar8 *) getenv ("FONTCONFIG_PATH");
     if (env)
     {
@@ -2491,6 +2491,14 @@ FcConfigGetPath (void)
     if (!path[i])
  goto bail1;
     strcpy ((char *) path[i], (const char *) dir);
+
+    // Fallback for Nixpkgs.
+    dir = (FcChar8 *) FALLBACK_FONTCONFIG_PATH;
+    path[i] = malloc (strlen ((char *) dir) + 1);
+    if (!path[i])
+        goto bail1;
+    strcpy ((char *) path[i], (const char *) dir);
+
     return path;

 bail1:

Can we please merge this? I just spent too many hours until I figured out why my application that depends on fontconfig via chromedriver did not work.

truvatech commented 1 year ago

I'm seeing this issue in my nested VM. Nixos host, nixos guest workstation VM. Whenever this pops up, chrome (well, in my case, Brave) freezes entirely for a good 15-20 seconds. I've been able to reproduce this issue any time I visit reddit and attempt to scroll down, for example. This is followed by errors related to accessing memory and the GPU process crashing (not currently on that VM. can share logs if useful later.

Not seeing this problem on an Arch guest, so unfortunately this is a big limiting factor in using nixos as a workstation guest

If something in the previous comments solves the issue, can someone indiciate where I have to make that change manually by any chance? I am not familiar enough with nixos/linux perhaps to understand where to add these snippets of code. Thanks

kfiz commented 1 year ago

If your working with docker tools this should work: https://github.com/NixOS/nixpkgs/issues/176081#issuecomment-1145825623

Or you could clone nixpkgs and apply this patch https://github.com/NixOS/nixpkgs/issues/176081#issuecomment-1145903568 to fontconfig and then install whatever package you want to use from your clone.

If not, then you should make sure that those environment variables are set correctly in the context of the binary that you are trying to use.