NixOS Rust development environment (Docker based)

A Rust programming language development environment can be somewhat cumbersome to set up under NixOS (e.g. to use CLevasseur/ta-lib-rust), so a solution using a Docker container is described in this article. – github.com/rust-lang (by rust-lang/people).

Normally a shell.nix as given below suffices to get rustup (see e.g. NixOS Wiki Rust) but I cannot always get these to work or don't want any unofficial overlays.

shell.nix example:

 1# https://nixos.wiki/wiki/Rust
 2
 3let
 4  # Pinned nixpkgs, deterministic. 
 5  pkgs = import (builtins.fetchGit {
 6    url = "https://github.com/NixOS/nixpkgs";
 7    ref = "refs/tags/21.11";
 8  }) {};
 9
10  # Rolling updates, not deterministic.
11  # pkgs = import (fetchTarball("channel:nixpkgs-unstable")) {};
12
13in pkgs.mkShell {
14  PKG_CONFIG_PATH = "${pkgs.openssl.dev}/lib/pkgconfig";
15
16  shellHook =
17    ''
18      export PS1="\[\033[01;32m\][\u@\h\[\033[01;37m\] |YourProjectName| \W\[\033[01;32m\]]\$\[\033[00m\] "
19    '';
20
21  # buildInputs = [ pkgs.cargo pkgs.rustc ];
22  buildInputs = [
23    pkgs.rustup
24    pkgs.rust-analyzer
25  ];
26}

or a more elaborate one for e.g. Tauri:

 1# https://nixos.wiki/wiki/Rust
 2
 3let
 4  # Pinned nixpkgs, deterministic. 
 5  pkgs = import (builtins.fetchGit {
 6    url = "https://github.com/NixOS/nixpkgs";
 7    ref = "refs/tags/21.11";
 8  }) {};
 9
10  # Rolling updates, not deterministic.
11  # pkgs = import (fetchTarball("channel:nixpkgs-unstable")) {};
12
13in pkgs.mkShell {
14  PKG_CONFIG_PATH = "${pkgs.openssl.dev}/lib/pkgconfig";
15
16  # buildInputs = [ pkgs.cargo pkgs.rustc ];
17  buildInputs = with pkgs; [
18    rustup
19    pkg-config
20    dbus
21    openssl
22    glib
23    gtk3
24    libsoup
25    webkitgtk
26    appimagekit
27  ];
28
29  PKGS_LD_LIBRARY_PATH = pkgs.lib.makeLibraryPath [ "libraries" ];
30  shellHook =
31    ''
32      export LD_LIBRARY_PATH="$PKGS_LD_LIBRARY_PATH:$LD_LIBRARY_PATH"
33      export PS1="\[\033[01;32m\][\u@\h\[\033[01;37m\] |TauriProjectNameHere| \W\[\033[01;32m\]]\$\[\033[00m\] "
34    '';
35}

Use the Makefile to build the container make rebuild and subsequently start the container make up and enter a development shell make shell which has a ~/Development binding (change to your path if needed).

Dockerfile

 1# Rust development environment.
 2
 3FROM debian:bullseye
 4
 5# Timezone is also in docker-compose file.
 6ENV HOME /root
 7ENV TZ Europe/Amsterdam
 8ENV SHELL /bin/bash
 9
10RUN apt-get update; \
11    apt-get upgrade -y; \
12    apt-get install -y procps sudo curl less vim-nox zip git pkg-config libssl-dev llvm clang build-essential bat exa fd-find; \
13    apt-get clean
14
15RUN sed -i "s#\smain\s*\$# main contrib non-free#" /etc/apt/sources.list
16RUN apt-get update
17# RUN apt-get install -y ta-lib --no-install-recommends
18
19# Create a non-root account with your user's uid and guid.
20RUN useradd -ms /bin/bash --uid 1000 --gid 100 rust
21# usermod -G audio,video rust;
22
23RUN echo "rust ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers
24
25# Install ta-lib.
26COPY ta-lib-0.4.0-src.tar.gz ta-lib-0.4.0-src.tar.gz
27RUN tar xvzf ta-lib-0.4.0-src.tar.gz ; \
28    rm ta-lib-0.4.0-src.tar.gz ; \
29    cd ta-lib ; \
30    ./configure ; \
31    make ; \
32    make install
33
34USER rust
35WORKDIR /home/rust
36ENV HOME /home/rust
37
38# Install and run rustup.
39# RUN curl https://sh.rustup.rs -sSf | sh
40RUN curl https://sh.rustup.rs -o rustup.sh ; \
41    chmod u+x ./rustup.sh ; \
42    ./rustup.sh -y
43
44# The DISPLAY variable is required to display on your desktop.
45ENV PS1='$ '
46ENV DISPLAY=":0"
47ENV PATH="$PATH:$HOME/.cargo/bin"
48
49# For access to X-server use the following command:
50#   xhost +LOCAL:
51#
52# RUN todo
53ENTRYPOINT ["/bin/bash"]

docker-compose.yaml

 1version: "2.0"
 2services:
 3  "rustalgotrading":
 4    image: rust-algotrading
 5    build: .
 6    stdin_open: true
 7    tty: true
 8    privileged: true
 9    ipc: host
10    environment:
11      - TZ=Europe/Amsterdam
12    network_mode: host
13    volumes:
14      - "/tmp/.X11-unix/:/tmp/.X11-unix/:ro"
15      - "~/Development:/home/rust/Development:rw"
16      - "~/.Xauthority:/home/rust/.Xauthority:rw"

Makefile

 1# Brings up the Docker container, which automatically starts a rust
 2# development environment. The attach can be used to connect to the
 3# command prompt in the container, where e.g. a Ctrl-c can be used to
 4# force a stop.
 5#
 6
 7NAME="docker-rustalgotrading-1"
 8
 9all: help
10
11up:
12    xhost +LOCAL:
13    docker-compose up -d
14
15down:
16    sync
17    docker-compose down
18
19# If problems persist after a force-down then manually restart Docker daemon.
20force-down:
21    sync
22    docker rm -f $(NAME)
23
24ls:
25    docker ps -a
26
27rebuild:
28    curl -O http://deac-fra.dl.sourceforge.net/project/ta-lib/ta-lib/0.4.0/ta-lib-0.4.0-src.tar.gz
29    xhost +LOCAL:
30    docker-compose build --no-cache
31
32build:
33    xhost +LOCAL:
34    docker-compose build
35
36attach:
37    xhost +LOCAL:
38    docker attach $(NAME)
39
40shell:
41    xhost +LOCAL:
42    docker exec -it $(NAME) /bin/bash
43
44help:
45    @grep '^[^  #:]\+:' Makefile | sed -e 's/:[^:]*//g'
46    echo "Use make -s for silent execution (e.g. make -s ls)"

Posts in this Series