Tell me your Development Storys with Visual Studio Code.
I Love VS-Code to build Container and use the Docker on the Terminal.
Actualy VS Code is my prefered ide for many use cases. On my latop, I use it with the kelvin.vscode-sshfs plugin in combination with the KeeAgent plugin in KeePass that serves the certificates for keyauth.
I love it that much, that I have code-server running all the time I added two helper scripts to a) add git credentials and b) define which plugins I want to have installed in the code-server. The beauty: everything can be used from a remote browser
my docker-compose.yml for a docker stack deployment:
The value for {CODER_IMAGE} is linuxserver/code-server:latest and the value for {CODER_DATA_DIR} is /config. Everything else are personal informations. The GIT_* environment parameters are specific to a helper script I wrote (see below). Everything else can be found in the dockerhub description of the image.
I do render this ātemplateā compose.yml with envsubst, which replaces the variables with the actual values, and pipe everything to docker stack deploy -c -
, which then deploys the rendered docker-compose.yml
---
version: '3.7'
x-deploy:
&default-deploy
mode: replicated
replicas: 1
restart_policy:
condition: any
services:
app:
image: ${CODER_IMAGE}
deploy:
<<: *default-deploy
labels:
- traefik.enable=true
- traefik.docker.network=web
- traefik.backend=code
- traefik.web.frontend.rule=Host:${CODER_FQDN}
- traefik.web.port=8443
- traefik.wss.protocol=https
- traefik.wss.frontend.rule=Host:${CODER_FQDN}
- traefik.wss.protocol=ws
- traefik.wss.port=8443
- traefik.frontend.headers.forceSTSHeader=true
- traefik.frontend.headers.STSSeconds=315360000
- traefik.frontend.headers.STSPreload=true
- traefik.frontend.headers.STSIncludeSubdomains=tr
- traefik.frontend.headers.browserXSSFilter=true
- traefik.frontend.headers.contentTypeNosniff=true
networks:
web: {}
environment:
PUID: ${CODER_ENV_PUID}
PGID: ${CODER_ENV_PGID}
TZ: ${CODER_ENV_TZ}
PASSWORD: '${CODER_ENV_PASSWORD}'
SUDO_PASSWORD: '${CODER_ENV_SUDO_PASSWORD}'
GIT_USERNAME_1: '${CODER_ENV_GIT_USERNAME_1}'
GIT_PASSWORD_1: '${CODER_ENV_GIT_PASSWORD_1}'
GIT_URL_1: '${CODER_ENV_GIT_URL_1}'
EXTENSIONS: >
ms-azuretools.vscode-docker
dotjoshjohnson.xml
ms-python.python
redhat.java
rebornix.ruby
samuelcolvin.jinjahtml
eamodio.gitlens
oderwat.indent-rainbow
coenraads.bracket-pair-colorizer
vincaslt.highlight-matching-tag
ivory-lab.jenkinsfile-support
vscoss.vscode-ansible
volumes:
- type: volume
source: data
target: '${CODER_DATA_DIR}'
configs:
- source: vs-extensions
target: ${CODER_DATA_DIR}/custom-cont-init.d/vs-extensions.sh
uid: '10001'
gid: '0'
mode: 444
- source: git-https-credentials
target: ${CODER_DATA_DIR}/custom-cont-init.d/vs-git-credentials.sh
uid: '10001'
gid: '0'
mode: 444
configs:
vs-extensions:
file: ./vs-extensions.sh
git-https-credentials:
file: ./vs-git-credentials.sh
volumes:
data:
...
networks:
web:
external: true
vs-extension.sh:
#!/bin/bash
if [ -z "${EXTENSIONS}" ];then
echo "Environment EXTENSIONS not provided, skipping "
exit 0
fi
extensions_dir="${HOME}/extensions"
# install missing extensions
for extension in ${EXTENSIONS}; do
if [ $(ls -1 ${extensions_dir} | grep -wc ${extension}) -eq 0 ];then
code-server --install-extension ${extension} --extensions-dir ${extensions_dir}
echo "extension installed: ${extension}"
else
echo "extension present: ${extension}"
fi
done
# cleanup old version of extension and oprhaned extension.
for installed_extension in $(code-server --extensions-dir ${extensions_dir} --list-extensions); do
uninstall_extension=true
for extension in ${EXTENSIONS}; do
if [ "${installed_extension,,}" == "${extension}" ]; then
uninstall_extension=false
# only keep latest versions
installed_versions=$(ls -1 ${extensions_dir} | grep ${extension})
latest_version=$(echo "${installed_versions}" | sort | tail -n 1 )
for version in ${installed_versions}; do
if [ "${version}" != "${latest_version}" ]; then
echo "deleting old extension version: ${version}"
rm -rf "${extensions_dir}/${version}"
fi
done
break;
fi
done
if [ "${uninstall_extension}" == "true" ]; then
code-server --uninstall-extension ${installed_extension} --extensions-dir ${extensions_dir}
echo "extension deleted: ${installed_extension}"
fi
done
vs-git-credentials.sh:
#!/bin/bash
rawurlencode() {
local string="${1}"
local strlen=${#string}
local encoded=""
local pos c o
for (( pos=0 ; pos<strlen ; pos++ )); do
c=${string:$pos:1}
case "$c" in
[-_.~a-zA-Z0-9] )
o="${c}"
;;
* )
printf -v o '%%%02x' "'$c"
esac
encoded+="${o}"
done
echo "${encoded}"
}
if [ $(git config --global credential.helper | grep "store" | wc -l) -eq 0 ]; then
git config --global credential.helper store
fi
rm ~/.git-credentials && touch ~/.git-credentials
for git_url in $(env | grep GIT_URL ); do
git_var=${git_url%=*} # extract key
i=${git_var##*_} # extract number from key
if [ "${i}" == "URL" ]; then
echo "https://$(rawurlencode ${GIT_USERNAME}):$(rawurlencode ${GIT_PASSWORD})@${GIT_URL}" >> ~/.git-credentials
elif [ ${i} -gt 0 ]; then
#inner eval build variable names, outter eval gets the value for the build variable names
USERNAME=$(eval echo \${$(eval echo GIT_USERNAME_\${i})})
PASSWORD=$(eval echo \${$(eval echo GIT_PASSWORD_\${i})})
URL=$(eval echo \${$(eval echo GIT_URL_\${i})})
echo "https://$(rawurlencode ${USERNAME}):$(rawurlencode ${PASSWORD})@${URL}" >> ~/.git-credentials
fi
done
The 2nd helper script parses all GIT_URL_{n} environment entries and fetches GIT_USERNAME_{n} and GIT_PASSWORD_{n} (where {n} is a number) to create as many entries in the ~/.git-credentials file as entries where defined .Of couse if your git server allows keyauth, then you would mount the key instead and do not use this script at all.