Skip to content

Commit 0540a0d

Browse files
author
Frankie Robertson
committed
Add devcontainer
1 parent f23ea1e commit 0540a0d

File tree

6 files changed

+614
-0
lines changed

6 files changed

+614
-0
lines changed

.devcontainer/Dockerfile

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
FROM julia:1.11
2+
3+
ARG TZ
4+
ENV TZ="$TZ"
5+
6+
ARG JULIA_VERSION=1.11
7+
8+
# Install basic development tools and iptables/ipset
9+
RUN apt-get update && apt-get install -y --no-install-recommends \
10+
less \
11+
git \
12+
procps \
13+
sudo \
14+
fzf \
15+
zsh \
16+
man-db \
17+
unzip \
18+
gnupg2 \
19+
gh \
20+
iptables \
21+
ipset \
22+
iproute2 \
23+
dnsutils \
24+
aggregate \
25+
jq \
26+
nano \
27+
vim \
28+
build-essential \
29+
curl \
30+
wget \
31+
ca-certificates \
32+
lsb-release \
33+
nodejs \
34+
npm \
35+
&& apt-get clean && rm -rf /var/lib/apt/lists/*
36+
37+
ARG USERNAME=julia
38+
ARG USER_UID=1000
39+
ARG USER_GID=$USER_UID
40+
41+
# Create the user with sudo privileges
42+
RUN groupadd --gid $USER_GID $USERNAME \
43+
&& useradd --uid $USER_UID --gid $USER_GID -m $USERNAME \
44+
&& echo $USERNAME ALL=\(root\) NOPASSWD:ALL > /etc/sudoers.d/$USERNAME \
45+
&& chmod 0440 /etc/sudoers.d/$USERNAME
46+
47+
# Persist bash and zsh history
48+
RUN SNIPPET="export PROMPT_COMMAND='history -a' && export HISTFILE=/commandhistory/.bash_history" \
49+
&& mkdir /commandhistory \
50+
&& touch /commandhistory/.bash_history \
51+
&& touch /commandhistory/.zsh_history \
52+
&& chown -R $USERNAME /commandhistory
53+
54+
# Set `DEVCONTAINER` environment variable to help with orientation
55+
ENV DEVCONTAINER=true
56+
57+
# Create workspace and Julia depot directories and set permissions
58+
RUN mkdir -p /workspace /home/$USERNAME/.julia && \
59+
chown -R $USERNAME:$USERNAME /workspace /home/$USERNAME/.julia
60+
61+
WORKDIR /workspace
62+
63+
ARG GIT_DELTA_VERSION=0.18.2
64+
RUN ARCH=$(dpkg --print-architecture) && \
65+
wget "https://github.com/dandavison/delta/releases/download/${GIT_DELTA_VERSION}/git-delta_${GIT_DELTA_VERSION}_${ARCH}.deb" && \
66+
dpkg -i "git-delta_${GIT_DELTA_VERSION}_${ARCH}.deb" && \
67+
rm "git-delta_${GIT_DELTA_VERSION}_${ARCH}.deb"
68+
69+
ARG ZSH_IN_DOCKER_VERSION=1.2.0
70+
RUN wget "https://github.com/deluan/zsh-in-docker/releases/download/v${ZSH_IN_DOCKER_VERSION}/zsh-in-docker.sh" && \
71+
chmod +x zsh-in-docker.sh && \
72+
./zsh-in-docker.sh \
73+
-t robbyrussell \
74+
-p git \
75+
-p ssh-agent \
76+
-p 'history-substring-search' \
77+
-a 'bindkey "\$terminfo[kcuu1]" history-substring-search-up' \
78+
-a 'bindkey "\$terminfo[kcud1]" history-substring-search-down' && \
79+
rm zsh-in-docker.sh
80+
81+
# Configure zsh history for the julia user
82+
RUN echo 'export HISTFILE=/commandhistory/.zsh_history' >> /home/$USERNAME/.zshrc && \
83+
echo 'export HISTSIZE=10000' >> /home/$USERNAME/.zshrc && \
84+
echo 'export SAVEHIST=10000' >> /home/$USERNAME/.zshrc && \
85+
echo 'setopt SHARE_HISTORY' >> /home/$USERNAME/.zshrc
86+
87+
# Set up Julia development environment
88+
USER $USERNAME
89+
90+
# Create Julia config directory - startup file will be copied by postCreateCommand
91+
RUN mkdir -p /home/$USERNAME/.julia/config
92+
93+
# Set Julia depot path
94+
ENV JULIA_DEPOT_PATH="/home/$USERNAME/.julia"
95+
96+
# Switch back to root for any final setup
97+
USER root
98+
99+
# Copy and set up firewall initialization script
100+
COPY init-firewall.sh /usr/local/bin/init-firewall.sh
101+
RUN chmod +x /usr/local/bin/init-firewall.sh
102+
103+
# Switch back to user
104+
USER $USERNAME

.devcontainer/README.md

Lines changed: 190 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,190 @@
1+
# DevContainer for ComputerAdaptiveTesting.jl
2+
3+
This directory contains the development container configuration for ComputerAdaptiveTesting.jl, based on the [Claude Code reference implementation](https://github.com/anthropics/claude-code/tree/main/.devcontainer).
4+
5+
## Features
6+
7+
- **Julia 1.11**: Latest stable Julia version with full development environment
8+
- **Claude Code Pattern**: Follows the same structure as Claude's reference devcontainer
9+
- **Security**: Includes firewall initialization for secure development
10+
- **Modern Shell**: Zsh with Oh My Zsh, Git integration, and history search
11+
- **Enhanced Git**: Git Delta for improved diffs and GitLens integration
12+
- **VS Code Extensions**: Pre-configured with Julia language support and development tools
13+
- **Persistent Storage**: Command history and Julia packages persist across rebuilds
14+
15+
## Quick Start
16+
17+
1. **Prerequisites**: Install VS Code and the Dev Containers extension
18+
2. **Open**: Open this repository in VS Code
19+
3. **Reopen in Container**: Command Palette → "Dev Containers: Reopen in Container"
20+
4. **Wait**: The container will build and set up the environment automatically (first build takes ~10 minutes)
21+
22+
## What's Included
23+
24+
### Architecture (Claude Code Pattern)
25+
- **Custom Dockerfile**: Multi-stage build with Julia base image
26+
- **Security-first**: Network capabilities and firewall initialization
27+
- **User-based**: Runs as `julia` user (not root) for security
28+
- **Persistent volumes**: Separate volumes for command history and Julia depot
29+
- **Workspace mounting**: Project mounted to `/workspace` following Claude pattern
30+
31+
### VS Code Extensions
32+
- Julia Language Support with full IntelliSense
33+
- GitLens for enhanced Git integration
34+
- Code Spell Checker
35+
- Markdown support with linting
36+
- JSON support
37+
- Jupyter support
38+
39+
### Shell Environment
40+
- **Zsh** with Oh My Zsh (robbyrussell theme)
41+
- **Git integration** with status in prompt
42+
- **History search** with arrow keys
43+
- **Persistent command history** across container restarts
44+
- **SSH agent** support
45+
46+
### Development Tools
47+
- **Claude Code CLI**: Full Claude Code experience in the container
48+
- **Git Delta**: Beautiful diffs with syntax highlighting
49+
- **GitHub CLI** for repository management
50+
- **fzf**: Fuzzy finder for command line
51+
- **Standard Unix tools**: less, vim, nano, man pages
52+
53+
### Julia Environment
54+
- **Project instantiation**: Main dependencies automatically installed
55+
- **Registry resolution**: Avoids local path issues by resolving from Julia General registry
56+
- **Startup script**: Automatic loading of development conveniences
57+
- **Depot persistence**: Julia packages cached across container rebuilds
58+
59+
### Security Features
60+
- **Firewall initialization**: Restricts network access to essential services
61+
- **Julia infrastructure**: Pre-configured access to Julia package registry, GitHub, etc.
62+
- **Network capabilities**: Required for firewall management
63+
- **Allowlist approach**: Only permitted domains/IPs are accessible
64+
65+
## Usage
66+
67+
### Running Tests
68+
```bash
69+
# In the container terminal (Zsh)
70+
julia --project=test test/runtests.jl
71+
```
72+
73+
### Building Documentation
74+
```bash
75+
julia --project=docs docs/make.jl
76+
```
77+
78+
### Interactive Development
79+
```bash
80+
# Start Julia REPL with project activated
81+
julia --project=.
82+
83+
# Install additional development tools as needed
84+
julia --project=. -e "using Pkg; Pkg.add([\"Revise\", \"OhMyREPL\", \"BenchmarkTools\"])"
85+
```
86+
87+
### Git Workflow
88+
```bash
89+
# Enhanced Git experience with Delta
90+
git diff # Beautiful syntax-highlighted diffs
91+
git log --oneline # Clean commit history
92+
gh pr create # Create pull requests via CLI
93+
```
94+
95+
### Claude Code Usage
96+
97+
The container is configured to support Claude Code. Installation requires Node.js/npm:
98+
99+
```bash
100+
# Install Node.js and npm first (if not already installed)
101+
sudo apt-get update && sudo apt-get install -y nodejs npm
102+
103+
# Install Claude Code CLI
104+
sudo npm install -g @anthropic-ai/claude-code
105+
106+
# Use Claude Code within the container
107+
claude # Start interactive Claude session
108+
claude "Explain this Julia function" < src/MyModule.jl
109+
claude --help # See all available options
110+
111+
# Example: Get help with Julia development
112+
claude "How can I optimize this Julia code for performance?"
113+
```
114+
115+
**Note**:
116+
- The firewall configuration may need to be adjusted to allow npm package downloads
117+
- Claude Code requires proper API authentication setup
118+
- Installation may require temporarily disabling the firewall or adding package repository domains to the allowlist
119+
120+
## File Structure
121+
122+
- `devcontainer.json` - Main container configuration (Claude Code pattern)
123+
- `Dockerfile` - Custom Julia development image with security features
124+
- `post-create.sh` - Setup script run after container creation
125+
- `init-firewall.sh` - Security initialization (adapted from Claude reference)
126+
- `startup.jl` - Julia startup script for development convenience
127+
- `README.md` - This documentation
128+
129+
## Key Differences from Simple Devcontainer
130+
131+
This implementation follows the Claude Code reference pattern with several advantages:
132+
133+
1. **Security-first**: Firewall and network restrictions
134+
2. **Better shell**: Zsh with full Git integration vs basic bash
135+
3. **Enhanced Git**: Delta for beautiful diffs, GitLens integration
136+
4. **User-based**: Runs as `julia` user vs root
137+
5. **Persistent storage**: Separate volumes for different data types
138+
6. **Build caching**: Optimized Docker layers for faster rebuilds
139+
140+
## Customization
141+
142+
You can customize the development environment by:
143+
144+
1. **Adding VS Code extensions**: Edit the `extensions` array in `devcontainer.json`
145+
2. **Modifying firewall rules**: Update `init-firewall.sh` to allow additional domains
146+
3. **Installing additional packages**: Modify `post-create.sh`
147+
4. **Changing Julia settings**: Update the `settings` in `devcontainer.json`
148+
149+
## Troubleshooting
150+
151+
### Container won't start
152+
- Check Docker is running and you have the necessary permissions
153+
- Try rebuilding: Command Palette → "Dev Containers: Rebuild Container"
154+
155+
### Network connectivity issues
156+
- Check firewall rules in `init-firewall.sh`
157+
- Firewall initialization failures are non-fatal but may limit network access
158+
159+
### Julia packages not installing
160+
- The environment resolves packages from the Julia General registry
161+
- Local Manifest.toml is removed to avoid path conflicts
162+
- First-time package installation takes longer due to compilation
163+
164+
### Slow startup
165+
- First build takes ~10 minutes due to installing development tools
166+
- First Julia package installation takes additional time for compilation
167+
- Subsequent starts are much faster due to Docker layer caching and Julia precompilation
168+
169+
## Performance Tips
170+
171+
1. **Package precompilation** is cached in persistent Julia depot volume
172+
2. **Docker build caching** speeds up container rebuilds
173+
3. **Command history persistence** maintains your workflow across sessions
174+
4. **Optimized package resolution** avoids local path conflicts
175+
176+
## Security Notes
177+
178+
This devcontainer includes security features following the Claude Code pattern:
179+
180+
- **Firewall restrictions**: Only essential domains are accessible
181+
- **Network capabilities**: Required for firewall management (NET_ADMIN, NET_RAW)
182+
- **Julia infrastructure**: Pre-configured access to necessary Julia services
183+
- **Non-root user**: Runs as `julia` user for reduced privilege
184+
185+
## Contributing
186+
187+
If you improve this devcontainer setup, please:
188+
1. Update this README with your changes
189+
2. Test with `devcontainer up --workspace-folder .`
190+
3. Submit a pull request following the project's contribution guidelines

.devcontainer/devcontainer.json

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
{
2+
"name": "ComputerAdaptiveTesting.jl Dev Environment",
3+
"build": {
4+
"dockerfile": "Dockerfile",
5+
"args": {
6+
"TZ": "${localEnv:TZ:America/Los_Angeles}",
7+
"JULIA_VERSION": "1.11",
8+
"GIT_DELTA_VERSION": "0.18.2",
9+
"ZSH_IN_DOCKER_VERSION": "1.2.0"
10+
}
11+
},
12+
"runArgs": [
13+
"--cap-add=NET_ADMIN",
14+
"--cap-add=NET_RAW"
15+
],
16+
"customizations": {
17+
"vscode": {
18+
"extensions": [
19+
"julialang.language-julia",
20+
"ms-vscode.vscode-json",
21+
"streetsidesoftware.code-spell-checker",
22+
"ms-vscode.test-adapter-converter",
23+
"ms-vscode.vscode-markdown",
24+
"davidanson.vscode-markdownlint",
25+
"ms-toolsai.jupyter",
26+
"eamodio.gitlens"
27+
],
28+
"settings": {
29+
"julia.executablePath": "/usr/local/julia/bin/julia",
30+
"julia.enableTelemetry": false,
31+
"julia.symbolCacheDownload": true,
32+
"julia.enableCrashReporter": false,
33+
"julia.lint.run": true,
34+
"julia.lint.missingRefDoc": "all",
35+
"julia.lint.disabledDirs": ["test"],
36+
"julia.format.indent": 4,
37+
"editor.formatOnSave": true,
38+
"editor.rulers": [92],
39+
"files.trimTrailingWhitespace": true,
40+
"files.insertFinalNewline": true,
41+
"terminal.integrated.defaultProfile.linux": "zsh",
42+
"terminal.integrated.profiles.linux": {
43+
"bash": {
44+
"path": "bash",
45+
"icon": "terminal-bash"
46+
},
47+
"zsh": {
48+
"path": "zsh"
49+
}
50+
}
51+
}
52+
}
53+
},
54+
"remoteUser": "julia",
55+
"mounts": [
56+
"source=computeradaptivetesting-julia-bashhistory-${devcontainerId},target=/commandhistory,type=volume",
57+
"source=computeradaptivetesting-julia-depot-${devcontainerId},target=/home/julia/.julia,type=volume"
58+
],
59+
"workspaceMount": "source=${localWorkspaceFolder},target=/workspace,type=bind,consistency=cached",
60+
"workspaceFolder": "/workspace",
61+
"containerEnv": {
62+
"JULIA_DEPOT_PATH": "/home/julia/.julia",
63+
"DEVCONTAINER": "true"
64+
},
65+
"postCreateCommand": "bash .devcontainer/post-create.sh",
66+
"forwardPorts": [8000, 8888],
67+
"portsAttributes": {
68+
"8000": {
69+
"label": "Development Server",
70+
"onAutoForward": "notify"
71+
},
72+
"8888": {
73+
"label": "Jupyter",
74+
"onAutoForward": "notify"
75+
}
76+
}
77+
}

0 commit comments

Comments
 (0)