├── .gitignore ├── Dockerfile ├── LICENSE.md ├── Makefile ├── README.md ├── completion.sh ├── entrypoint.sh └── welcome.sh /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | test/ -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM codercom/code-server AS su-exec 2 | USER root 3 | RUN curl -o /usr/local/bin/su-exec.c https://raw.githubusercontent.com/ncopa/su-exec/master/su-exec.c && \ 4 | apt-get update && \ 5 | apt-get install -y --no-install-recommends gcc libc-dev && \ 6 | gcc -Wall \ 7 | /usr/local/bin/su-exec.c -o /usr/local/bin/su-exec && \ 8 | chown root:root /usr/local/bin/su-exec && \ 9 | chmod 0755 /usr/local/bin/su-exec 10 | 11 | FROM codercom/code-server 12 | USER root 13 | COPY --from=su-exec /usr/local/bin/su-exec /su-exec 14 | 15 | # Docker 16 | ARG DOCKER_COMPOSE_VERSION=1.24.1 17 | RUN apt-get update && \ 18 | apt-get install -y \ 19 | apt-transport-https ca-certificates curl gnupg-agent software-properties-common figlet && \ 20 | curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add - && \ 21 | add-apt-repository \ 22 | "deb [arch=amd64] https://download.docker.com/linux/ubuntu \ 23 | $(lsb_release -cs) \ 24 | stable" && \ 25 | apt-get update && \ 26 | apt-get install -y docker-ce-cli && \ 27 | curl -L "https://github.com/docker/compose/releases/download/${DOCKER_COMPOSE_VERSION}/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose && \ 28 | chmod +x /usr/local/bin/docker-compose && \ 29 | curl -L "https://raw.githubusercontent.com/docker/compose/${DOCKER_COMPOSE_VERSION}/contrib/completion/bash/docker-compose" -o /etc/bash_completion.d/docker-compose && \ 30 | curl -L "https://raw.githubusercontent.com/nicferrier/docker-bash-completion/master/docker-complete" -o /etc/bash_completion.d/docker && \ 31 | curl -sf https://raw.githubusercontent.com/lukaszlach/clip/master/docker-clip -o /usr/libexec/docker/cli-plugins/docker-clip && \ 32 | chmod +x /usr/libexec/docker/cli-plugins/docker-clip && \ 33 | apt-get install -y \ 34 | bash bash-completion \ 35 | curl wget \ 36 | make git jq htop gettext strace \ 37 | iproute2 bind9-host iputils-ping socat \ 38 | tldr && \ 39 | rm -rf /var/lib/apt/lists/* 40 | # Kubernetes 41 | RUN curl -sSfL https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/linux/amd64/kubectl -o /usr/bin/kubectl && \ 42 | chmod +x /usr/bin/kubectl 43 | 44 | ENTRYPOINT ["bash", "/entrypoint.sh"] 45 | CMD ["--allow-http", "--no-auth"] 46 | COPY entrypoint.sh completion.sh welcome.sh / -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Łukasz Lach 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | Copyright (c) 2019 Coder Technologies Inc. 24 | https://github.com/cdr/code-server/blob/master/LICENSE -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | build: 2 | docker build -t code-editor . 3 | 4 | list: 5 | docker images | grep code-editor 6 | 7 | run: 8 | rm -rf test/ && mkdir test/ 9 | docker run --rm -it --name code-editor -v /var/run/docker.sock:/var/run/docker.sock -e EDITOR_UID=$$(id -u) -e EDITOR_GID=$$(id -g) -e EDITOR_CLONE="https://github.com/lukaszlach/orca.git" -e EDITOR_EXTENSIONS="peterjausovec.vscode-docker" -e EDITOR_BANNER=code-container -e EDITOR_LOCALHOST_ALIASES="local;localtest.me" -e EDITOR_PASSWORD=docker -e EDITOR_PORT=8443 -p 8443:8443 -v $$(pwd)/test:/files --hostname workshop --pid host code-editor 10 | 11 | push: 12 | docker tag code-editor lukaszlach/code-container 13 | docker push lukaszlach/code-container 14 | 15 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # lukaszlach / code-container 2 | 3 | [![Docker pulls](https://img.shields.io/docker/pulls/lukaszlach/code-container.svg?label=docker+pulls)](https://hub.docker.com/r/lukaszlach/code-container) 4 | 5 | [Microsoft Visual Studio Code](https://github.com/Microsoft/vscode) running in a Docker container, accessible through the web browser. 6 | 7 | ![](https://user-images.githubusercontent.com/5011490/59969073-b85e9880-9545-11e9-8d38-e58435cb26f9.png) 8 | 9 | Code Container is based on the [Code Server](https://github.com/cdr/code-server) project and extends it by adding: 10 | 11 | * configuration with environment variables 12 | * possibility to run as any user and group, preserving credentials for files created in the editor 13 | * automatic installation of editor extensions 14 | * additional tools like `make`, `strace`, `envsubst` or `tldr` 15 | * Docker client and docker-compose with bash completion 16 | * Docker client experimental features enabled 17 | * Docker client plugins support with [Docker Client Plugins Manager](https://github.com/lukaszlach/clip) pre-installed 18 | * Kubernetes client 19 | * possibility to run in `pid` and `net` host modes, useful when doing Docker workshops 20 | * detection of Docker Desktop and setting `localhost` accordingly 21 | 22 | ## Configuration 23 | 24 | Set an environment variable to configure the editor entrypoint: 25 | 26 | * `EDITOR_UID`, `EDITOR_GID` - optional, user id and group id to use, if you wish to map the host values directly pass `-e EDITOR_UID=$(id -u) -e EDITOR_GID=$(id -g)` 27 | * `EDITOR_EXTENSIONS` - optional, semicolon-delimited list of extensions to install 28 | * `EDITOR_PASSWORD` - optional, password required to access the editor 29 | * `EDITOR_CLONE` - optional, repository URL to clone in the editor home directory 30 | * `EDITOR_LOCALHOST_ALIASES` - optional, semicolon-delimited list of host names to map to localhost; if Docker Desktop is detected, `host.docker.internal` becomes an alias for `localhost` inside the editor container 31 | * `EDITOR_BANNER` - optional, banner to display in a new terminal window 32 | * `EDITOR_LINE_ENDINGS` - optional, either `LF` (default) or `CRLF` 33 | * `EDITOR_PORT` - optional, port number to use, useful when using host network mode to run the editor 34 | 35 | ## Running 36 | 37 | Docker container requires mounting `/var/run/docker.sock` from the host system. Set up a volume on target `/files` directory to preserve your work, files created in the editor will respect the user and group ids used to run the editor. 38 | 39 | Basic example: 40 | 41 | ```bash 42 | docker run -d --name code-container --hostname code-container \ 43 | -v /var/run/docker.sock:/var/run/docker.sock \ 44 | -e EDITOR_UID=$(id -u) -e EDITOR_GID=$(id -g) \ 45 | -v "$HOME:/files" \ 46 | -p 8443:8443 \ 47 | lukaszlach/code-container 48 | ``` 49 | 50 | Complex example: 51 | 52 | ```bash 53 | docker run -d --pid host --name code-container --hostname code-container \ 54 | -v /var/run/docker.sock:/var/run/docker.sock \ 55 | -v "$HOME:/files" \ 56 | -e EDITOR_UID=$(id -u) -e EDITOR_GID=$(id -g) \ 57 | -e EDITOR_CLONE="https://github.com/lukaszlach/orca.git" \ 58 | -e EDITOR_EXTENSIONS="peterjausovec.vscode-docker" \ 59 | -e EDITOR_BANNER=Hello \ 60 | -e EDITOR_LOCALHOST_ALIASES="host.local;localtest.me" \ 61 | -e EDITOR_PASSWORD=docker \ 62 | -e EDITOR_PORT=8443 \ 63 | -p 8443:8443 \ 64 | lukaszlach/code-container 65 | ``` 66 | 67 | > Use `--pid host` if you want `htop`, `ps` and similar tools to work like on the host system. 68 | 69 | > Set the `--hostname` so it looks nice in the inline terminal. 70 | 71 | Example with Docker-in-Docker: 72 | 73 | ```bash 74 | docker run -d --privileged --name dind docker:stable-dind 75 | DIND_IP=$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' dind) 76 | docker run -d --name code-container --hostname code-container \ 77 | -e DOCKER_HOST="tcp://${DIND_IP}:2375" 78 | -e EDITOR_CLONE="https://github.com/lukaszlach/orca.git" \ 79 | -e EDITOR_EXTENSIONS="peterjausovec.vscode-docker" \ 80 | lukaszlach/code-container 81 | ``` 82 | 83 | ## Building 84 | 85 | ```bash 86 | docker build -t lukaszlach/code-container . 87 | ``` 88 | 89 | ## Contributors 90 | 91 | [![](https://sourcerer.io/fame/lukaszlach/lukaszlach/code-container/images/0)](https://sourcerer.io/fame/lukaszlach/lukaszlach/code-container/links/0)[![](https://sourcerer.io/fame/lukaszlach/lukaszlach/code-container/images/1)](https://sourcerer.io/fame/lukaszlach/lukaszlach/code-container/links/1)[![](https://sourcerer.io/fame/lukaszlach/lukaszlach/code-container/images/2)](https://sourcerer.io/fame/lukaszlach/lukaszlach/code-container/links/2)[![](https://sourcerer.io/fame/lukaszlach/lukaszlach/code-container/images/3)](https://sourcerer.io/fame/lukaszlach/lukaszlach/code-container/links/3)[![](https://sourcerer.io/fame/lukaszlach/lukaszlach/code-container/images/4)](https://sourcerer.io/fame/lukaszlach/lukaszlach/code-container/links/4)[![](https://sourcerer.io/fame/lukaszlach/lukaszlach/code-container/images/5)](https://sourcerer.io/fame/lukaszlach/lukaszlach/code-container/links/5)[![](https://sourcerer.io/fame/lukaszlach/lukaszlach/code-container/images/6)](https://sourcerer.io/fame/lukaszlach/lukaszlach/code-container/links/6)[![](https://sourcerer.io/fame/lukaszlach/lukaszlach/code-container/images/7)](https://sourcerer.io/fame/lukaszlach/lukaszlach/code-container/links/7) 92 | 93 | ## License 94 | 95 | MIT License 96 | 97 | Copyright (c) 2019 Łukasz Lach 98 | 99 | Permission is hereby granted, free of charge, to any person obtaining a copy 100 | of this software and associated documentation files (the "Software"), to deal 101 | in the Software without restriction, including without limitation the rights 102 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 103 | copies of the Software, and to permit persons to whom the Software is 104 | furnished to do so, subject to the following conditions: 105 | 106 | The above copyright notice and this permission notice shall be included in all 107 | copies or substantial portions of the Software. 108 | 109 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 110 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 111 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 112 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 113 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 114 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 115 | SOFTWARE. -------------------------------------------------------------------------------- /completion.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | for bcfile in /etc/bash_completion.d/* ; do 3 | . "$bcfile" 4 | done -------------------------------------------------------------------------------- /entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | editor_exec() { 3 | /su-exec "$EDITOR_USER_NAME" "$@" 4 | } 5 | if [ -z "${DOCKER_HOST}" ]; then 6 | if [ ! -e /var/run/docker.sock ]; then 7 | echo "Error: /var/run/docker.sock not mounted" 8 | exit 1 9 | fi 10 | # Expose Docker unix socket as a TCP server 11 | # https://github.com/cdr/code-server/issues/436 12 | socat TCP-LISTEN:2376,reuseaddr,fork UNIX-CONNECT:/var/run/docker.sock &>/dev/null & 13 | export DOCKER_HOST=tcp://127.0.0.1:2376 14 | fi 15 | EDITOR_USER_NAME=editor 16 | EDITOR_GROUP_NAME=editor 17 | EDITOR_UID="${EDITOR_UID:-10001}" 18 | EDITOR_GID="${EDITOR_GID:-10001}" 19 | EDITOR_USER="${EDITOR_UID}:${EDITOR_GID}" 20 | 21 | groupadd -g "$EDITOR_GID" "$EDITOR_GROUP_NAME" || \ 22 | groupmod -n "$EDITOR_GROUP_NAME" $(getent group "$EDITOR_GID" | cut -d: -f1) 23 | useradd -m -u "$EDITOR_UID" -g "$EDITOR_GID" -G 0 -s /bin/bash "$EDITOR_USER_NAME" 24 | 25 | if mountpoint /files >/dev/null 2>&1; then 26 | editor_exec mkdir -p "/files/project" 27 | editor_exec ln -sf "/files/project" "/home/$EDITOR_USER_NAME/project" 28 | else 29 | editor_exec mkdir -p "/home/$EDITOR_USER_NAME/project" 30 | fi 31 | editor_exec cp -f /completion.sh "/home/$EDITOR_USER_NAME/.bash_completion" 32 | cd "/home/$EDITOR_USER_NAME/project" 33 | if [ ! -z "$EDITOR_CLONE" ]; then 34 | editor_exec git clone "$EDITOR_CLONE" || true 35 | fi 36 | 37 | # Profile 38 | touch /tmp/.versions 39 | docker -v >> /tmp/.versions 40 | docker-compose -v >> /tmp/.versions 41 | echo ". /welcome.sh" >> "/home/$EDITOR_USER_NAME/.bashrc" 42 | 43 | # Extensions 44 | if [ ! -z "$EDITOR_EXTENSIONS" ]; then 45 | IFS=";" 46 | for EXTENSION in $EDITOR_EXTENSIONS; do 47 | editor_exec code-server --install-extension "$EXTENSION" || true 48 | done 49 | fi 50 | 51 | # Hosts 52 | if [ ! -z "$EDITOR_LOCALHOST_ALIASES" ]; then 53 | set +e 54 | LOCALHOST="127.0.0.1" 55 | DOCKER_INTERNAL=$(host host.docker.internal | head -n1 | awk '{print $NF}') 56 | if [ ! -z "$DOCKER_INTERNAL" ]; then 57 | LOCALHOST="$DOCKER_INTERNAL" 58 | # include special hostname as an alias for localhost 59 | EDITOR_LOCALHOST_ALIASES="localhost;$EDITOR_LOCALHOST_ALIASES" 60 | fi 61 | set -e 62 | IFS=";" 63 | for LOCALHOST_ALIAS in $EDITOR_LOCALHOST_ALIASES; do 64 | echo "$LOCALHOST $LOCALHOST_ALIAS" >> /etc/hosts 65 | done 66 | fi 67 | 68 | EDITOR_LINE_ENDINGS="${EDITOR_LINE_ENDINGS:-LF}" 69 | if [ "$EDITOR_LINE_ENDINGS" != "CRLF" ]; then 70 | editor_exec git config --global core.autocrlf false 71 | editor_exec mkdir -p /home/editor/.local/share/code-server/User 72 | editor_exec echo '{"files.eol": "\n"}' > /home/editor/.local/share/code-server/User/settings.json 73 | fi 74 | 75 | EDITOR_PORT="${EDITOR_PORT:-8443}" 76 | if [ ! -z "$EDITOR_PASSWORD" ]; then 77 | export PASSWORD="$EDITOR_PASSWORD" 78 | editor_exec dumb-init code-server --port "$EDITOR_PORT" --allow-http 79 | else 80 | editor_exec dumb-init code-server --port "$EDITOR_PORT" --allow-http --no-auth 81 | fi 82 | -------------------------------------------------------------------------------- /welcome.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | . ~/.bash_completion 3 | if [ ! -z "$EDITOR_BANNER" ]; then 4 | figlet "$EDITOR_BANNER" 5 | fi 6 | cat /tmp/.versions 7 | echo 8 | --------------------------------------------------------------------------------