Reputation: 1079
I put together a small example of how I manage my development environment with Docker from within Emacs. The idea is, rather than having multiple files in folders that interrelate to each other and thus make it hard to track transitional changes, to have one org-file and just tangle the individual files and even execute some of the source code blocks within the org file for convenience with the use of some Emacs packages. Below I try to describe my reasoning and I am grateful for advise on how to streamline things and also alternatives to my approach. Maybe though it can also prove helpful for others who aim for similar workflows. Can I improve something, by following best practices and the likes? I am particularly concerned about the local-file variable that defines the docker-image name on a per-file basis and which I need to read out in several places in a quite cumbersome way
# -*- image_name: "test_env"; -*-
* Environment
:PROPERTIES:
:header-args: :results output :mkdirp yes
:END:
** requirements.txt
#+BEGIN_SRC conf :tangle requirements.txt
numpy
#+END_SRC
** Start docker
#+BEGIN_SRC sh :dir "/sudo::"
sudo service docker start
#+END_SRC
** Dockerfile
Use [ob-docker-build][1] to build the docker images upon pressing C-c C-c. The image
name is grabbed from the file-local variable at the top of this file. This file
can also be tangled to disk.
#+BEGIN_SRC docker-build :dir "." :tag (symbol-value 'image_name) :tangle Dockerfile
FROM python:3.8-slim-buster
ENV VIRTUAL_ENV=/opt/venv
RUN python3 -m venv $VIRTUAL_ENV
# Make sure we use the virtualenv:
ENV PATH="$VIRTUAL_ENV/bin:$PATH"
COPY requirements.txt .
RUN pip install --quiet --no-cache-dir -r requirements.txt
WORKDIR /app
# just for keeping the container running
CMD tail -f /dev/null
#+END_SRC
** run_docker.sh
This script can either be tangled to disk or is executed automatically by
org-sbe in the python application below
#+HEADER: :var image_name=(symbol-value 'image_name)
#+name: run_docker
#+BEGIN_SRC bash :tangle run_docker.sh :tangle-mode (identity #o755) :results output
#!/bin/bash
SBX_DIR=$(realpath $(dirname $0))
# generate some id for the container
CONTAINER_NAME=$(uuidgen | md5sum | awk '{ print $1 }' | cut -c -12)
if [ $# -eq 0 ]; then
ARGS=$SHELL
else
ARGS=$@
fi
DOCKER="docker run"
DOCKER_ARGS=(
--name "$CONTAINER_NAME"
-v $HOME:$HOME
-v "$SBX_DIR":"$SBX_DIR"
--rm
--user $(id -u):$(id -g)
-w $SBX_DIR
-itd ${image_name}
$ARGS
)
$DOCKER ${DOCKER_ARGS[@]}
#+END_SRC
** python
Use the [docker-tramp][1] package to attach to a running container. C-c C-c on the
block below causes the run-docker src-block to be executed. The resulting ID of
the container is then used here to attach to this running instance
#+BEGIN_SRC python :dir (concat "/docker:" (org-sbe run_docker) ":") :results output
print('hello')
#+END_SRC
What is taking precedence here?
# -*- foo: "one"; -*-
#+PROPERTY: header-args :var foo=two
#+PROPERTY: foo=three
* first
:PROPERTIES:
:foo: four
:END:
** second
:PROPERTIES:
:foo: five
:END:
#+HEADER: foo=(symbol-value 'foo)
#+BEGIN_SRC bash :var foo=(org-macro--get-property "foo" "")
echo $foo
#+END_SRC
Upvotes: 5
Views: 1352
Reputation: 2301
Re:
I am particularly concerned about the local-file variable that defines the docker-image name on a per-file basis and which I need to read out in several places in a quite cumbersome way
You can define a property and access in text and in header args:
:PROPERTIES:
:foo: bar
:END:
You can access the foo property like this: {{{property(foo)}}}.
And you can access it in header args like this:
#+BEGIN_SRC bash :var foo=(org-macro--get-property "foo" "")
echo $foo # prints bar
#+END_SRC
Upvotes: 3