Skip to content

Commit 9d94e09

Browse files
committed
Begin the devcontainer setup
1 parent 3731001 commit 9d94e09

File tree

5 files changed

+153
-18
lines changed

5 files changed

+153
-18
lines changed

.devcontainer/devcontainer.json

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
{
2+
"build": {
3+
"dockerfile": "../docker/app/Dockerfile",
4+
"context": ".."
5+
},
6+
7+
"mounts": [
8+
// Use a "docker outside of docker" setup where we reuse the host's docker daemon:
9+
// https://github.com/microsoft/vscode-dev-containers/tree/main/containers/docker-from-docker
10+
{
11+
"source": "/var/run/docker.sock",
12+
"target": "/var/run/docker.sock",
13+
"type": "bind"
14+
}
15+
],
16+
17+
"workspaceMount": "source=${localWorkspaceFolder},target=/home/philomena/philomena,type=bind",
18+
"workspaceFolder": "/home/philomena/philomena",
19+
20+
"containerEnv": {
21+
"HOST_WORKSPACE": "${localWorkspaceFolder}"
22+
},
23+
24+
// While technically optional, --init enables an init process to properly handle
25+
// signals and ensure Zombie Processes are cleaned up.
26+
"runArgs": [
27+
"--init",
28+
29+
// Do some initial setup tasks at runtime.
30+
"--entrypoint",
31+
"${containerWorkspaceFolder}/.devcontainer/docker-init.sh"
32+
],
33+
34+
// Make sure our custom `docker-init.sh` script is run at startup
35+
"overrideCommand": false,
36+
37+
"customizations": {
38+
"vscode": {
39+
"extensions": [
40+
// Rust LSP
41+
"rust-lang.rust-analyzer",
42+
43+
// Elixir LSP
44+
"lexical-lsp.lexical",
45+
46+
// Dockerfile LSP
47+
"ms-azuretools.vscode-docker",
48+
49+
// Github Actions LSP
50+
"github.vscode-github-actions",
51+
52+
// Bash LSP
53+
"mads-hartmann.bash-ide-vscode",
54+
55+
// `.slime` syntax highlighting
56+
"xolan.slime",
57+
58+
// `.js`, `.ts` linter
59+
"dbaeumer.vscode-eslint",
60+
61+
// `.css` linter
62+
"stylelint.vscode-stylelint",
63+
64+
// `.js`, `.ts`. `.css`, `.json`, `.yaml`, `.md` formatter
65+
"esbenp.prettier-vscode",
66+
67+
// Spell checker enforced on CI
68+
"tekumara.typos-vscode",
69+
70+
// `.toMatchInlineSnapshot()` syntax highlighting
71+
"tlent.jest-snapshot-language-support"
72+
]
73+
}
74+
}
75+
}

.devcontainer/docker-init.sh

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
#!/usr/bin/env bash
2+
3+
set -euo pipefail
4+
5+
. "$(dirname "${BASH_SOURCE[0]}")/../scripts/lib.sh"
6+
7+
# Add the current user to the docker group to allow running docker commands
8+
# without sudo. We have to do this right at the start of the container instead
9+
# of the build time because the docker socket is mounted only at runtime.
10+
docker_gid=$(stat -c '%g' /var/run/docker.sock)
11+
12+
if [[ "${docker_gid}" == '0' ]]; then
13+
die "Unsupported configuration: docker socket is owned by root"
14+
fi
15+
16+
# This is really annoying, but to provide sudo-less access to the docker socket,
17+
# we need to add the current user to the group that owns the socket. Because we
18+
# mount it from the host the group may have arbitrary ID that we can't easily
19+
# control.
20+
#
21+
# There can also be an existing group in the container with the ID of the host
22+
# docker socket group, which is very likely to happen given that the usual docker
23+
# group has ID 999 and Alpine Linux uses this GID for the `ping` group:
24+
# https://github.com/alpinelinux/docker-alpine/issues/323
25+
existing_group=$(getent group "${docker_gid}")
26+
27+
if [ "$existing_group" = '' ]; then
28+
step sudo groupadd --gid "${docker_gid}" docker-host
29+
else
30+
info "Group with the host docker socket GID already exists: ${existing_group}. Reusing it."
31+
fi
32+
33+
user=$(id -u -n)
34+
35+
if [ "$(id "$user" | grep -E "groups=.*(=|,)${docker_gid}\\(")" = '' ]; then
36+
step sudo usermod --append --groups "${docker_gid}" "$user"
37+
else
38+
info "User ${user} is already in the group ${docker_gid}. No need to add it again."
39+
fi
40+
41+
step exec sleep infinity

.gitignore

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ philomena-*.tar
2929
npm-debug.log
3030

3131
# The directory NPM downloads your dependencies sources to.
32-
/assets/node_modules/
32+
node_modules/
3333

3434
# Since we are building assets from assets/,
3535
# we ignore priv/static. You may want to comment
@@ -64,9 +64,3 @@ npm-debug.log
6464

6565
# Vitest coverage
6666
/assets/coverage
67-
68-
# The tool output directory is used by the repo init script to store various
69-
# tools that are used for development. We use this repo-local folder and avoid
70-
# using system-wide directories to prevent polluting the dev's environment which
71-
# may be shared with other projects.
72-
.tools

docker-compose.yml

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ services:
1111
build:
1212
context: .
1313
dockerfile: ./docker/app/Dockerfile
14+
15+
command: run-development
16+
1417
environment:
1518
- MIX_ENV=dev
1619
- PGPASSWORD=postgres
@@ -46,12 +49,8 @@ services:
4649
working_dir: /srv/philomena
4750
tty: true
4851

49-
# The `HOST_USER` is set by the wrapper script. This prevents the polluting
50-
# the repo directory with root-owned files.
51-
user: ${HOST_USER:-root}
52-
5352
volumes:
54-
- .:/srv/philomena
53+
- ${HOST_WORKSPACE-.}:/home/philomena/philomena
5554
- app_cargo_data:/srv/philomena/.cargo
5655
- app_build_data:/srv/philomena/_build
5756
- app_deps_data:/srv/philomena/deps
@@ -75,7 +74,7 @@ services:
7574
image: opensearchproject/opensearch:2.19.1
7675
volumes:
7776
- opensearch_data:/usr/share/opensearch/data
78-
- ./docker/opensearch/opensearch.yml:/usr/share/opensearch/config/opensearch.yml
77+
- ${HOST_WORKSPACE-.}/docker/opensearch/opensearch.yml:/usr/share/opensearch/config/opensearch.yml
7978
attach: false
8079
ulimits:
8180
nofile:
@@ -91,7 +90,7 @@ services:
9190
environment:
9291
- JCLOUDS_FILESYSTEM_BASEDIR=/srv/philomena/priv/s3
9392
volumes:
94-
- .:/srv/philomena
93+
- ${HOST_WORKSPACE-.}:/srv/philomena
9594
attach: false
9695

9796
web:
@@ -110,7 +109,7 @@ services:
110109
user: ${HOST_USER:-root}
111110

112111
volumes:
113-
- .:/srv/philomena
112+
- ${HOST_WORKSPACE-.}:/srv/philomena
114113

115114
environment:
116115
- AWS_ACCESS_KEY_ID=local-identity

docker/app/Dockerfile

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,14 @@ RUN ( \
3636
&& mix local.hex --force \
3737
&& mix local.rebar --force
3838

39+
# Dev-only tools
40+
RUN apk add --update \
41+
bottom \
42+
docker-cli-compose \
43+
# Needed for the `usermod` command
44+
shadow \
45+
sudo
46+
3947
ADD https://api.github.com/repos/philomena-dev/cli_intensities/git/refs/heads/master /tmp/cli_intensities_version.json
4048
RUN git clone --depth 1 https://github.com/philomena-dev/cli_intensities /tmp/cli_intensities \
4149
&& cd /tmp/cli_intensities \
@@ -47,11 +55,18 @@ RUN git clone --depth 1 https://github.com/philomena-dev/mediatools /tmp/mediato
4755
&& cd /tmp/mediatools \
4856
&& make -j$(nproc) install
4957

50-
# docker-compose configures a bind-mount of the repo root dir to /srv/philomena
51-
ENV PATH=$PATH:/srv/philomena/docker/app
58+
# Create a non-root user to avoid polluting the bind-mounted directories with
59+
# root-owned files on the host machine.
60+
ARG USER=philomena
61+
ARG CONTAINER_WORKSPACE=/home/$USER/philomena
62+
63+
# docker-compose configures a bind-mount of the repo root dir to $REPO
5264
ENV PATH=$PATH:/root/.cargo/bin
65+
ENV PATH=$PATH:$CONTAINER_WORKSPACE/docker/app
66+
ENV PATH=$PATH:$CONTAINER_WORKSPACE/scripts/path
67+
68+
WORKDIR $CONTAINER_WORKSPACE
5369

54-
WORKDIR /app
5570
RUN --mount=source=./scripts,target=./scripts ./scripts/install/typos.sh
5671
RUN --mount=source=./scripts,target=./scripts ./scripts/install/shellcheck.sh
5772
RUN --mount=source=./package.json,target=./package.json \
@@ -61,3 +76,14 @@ RUN --mount=source=./package.json,target=./package.json \
6176
EXPOSE 5173
6277

6378
CMD ["run-development"]
79+
80+
# The UID of 1000 is the default for most Linux distributions, which should make
81+
# this user map to the default user on the host system for bind-mounted volumes.
82+
#
83+
# However, if you are running this in a devcontainer via VSCode, then it'll update
84+
# the UID/GID of this user to match the UID/GID of the user on the host automatically:
85+
#: https://code.visualstudio.com/remote/advancedcontainers/add-nonroot-user#_specifying-the-default-container-user
86+
RUN adduser $USER --uid 1000 --shell /bin/bash --disabled-password \
87+
&& echo "$USER ALL=(ALL) NOPASSWD:ALL" > /etc/sudoers.d/$USER
88+
89+
USER $USER

0 commit comments

Comments
 (0)