Introducing your own settings for Remote Containers, a VS Code god extension Official sample is open to the public, but since it is difficult to use as it is, I will introduce the settings edited to make it easy for me to use. In addition, all the configuration files introduced in this article are published in the following repositories (including those in environments not introduced). https://github.com/sabure500/remote-container-sample
Also, I thought it would be good to use Remote Containers, so I'm playing around with the settings to make it easier to use, but since this article "wants to create" the strongest local environment, there is an idea that this is better. I would be grateful if you could tell me
It's an extension of VS Code that allows you to open and work in VS Code inside a container. Since you can open VS Code directly in the container and work, you can sandbox the development environment and develop in a place that does not affect the local machine at all. There are other similar extension series, "Remote SSH" and "Remote WSL", which allow you to open VS Code and work in the SSH destination or WSL respectively. Please refer to Official Site for details of each.
To create a development environment with VSCode Remote Containers, you need to install the following two Conversely, if you have the following two, you can create an environment such as Node, python, Go, Java etc. without putting anything else on the local machine.
Docker Desktop for Windows or Mac Download the installer from the official page below https://www.docker.com/products/docker-desktop
Visual Studio Code
Download from the official page below https://code.visualstudio.com/docs
Since Remote Containers is a normal extension, you can install it from there as it will appear in the list by starting it after installing VS Code, selecting the extension from the tab on the left and searching for "Remote Container". Alternatively, you can install it from the marketplace page below. https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers
After starting the location where the Remote Containers configuration file, which will be introduced later, is located as Workspace, click the green "> <" mark at the bottom left of VS Code and select "Remote-Containers: Reopen in Container".
Environment construction in Remote Containers is done by placing devcontainer.json, a configuration file for Remote Containers, and Dockerfile (or docker-compose.yaml, etc.) in the .devcontainer directory. I will introduce the settings for each environment
GoogleCloudSDK I also use Remote Containers when using Google Cloud SDK commands in my local environment. The configuration file is published below, and basically anyone can use the same Google Cloud SDK environment immediately by using this as it is. Describe the settings for building the environment The whole directory structure is as follows
.
├ .devcontainer
├ devcontainer.json
├ Dockerfile
├ .config/fish/config.fish
└ .local/share/fish/fish_history
Dockerfile File for creating a container to be used as an actual development environment First give the big picture, then explain each line
Dockerfile
FROM google/cloud-sdk:297.0.1-alpine
# ===== common area =====
RUN apk add --no-cache fish git openssh curl
COPY .config/fish/config.fish /root/.config/fish/config.fish
# =======================
# ===== kubernetes resource install =====
ENV KUBECTL_VERSION 1.18.4
ENV KUSTOMIZE_VERSION 3.1.0
ENV ARGOCD_VERSION 1.5.2
RUN curl -sfL -o /usr/local/bin/kubectl https://storage.googleapis.com/kubernetes-release/release/v${KUBECTL_VERSION}/bin/linux/amd64/kubectl \
&& curl -sfL -o /usr/local/bin/kustomize https://github.com/kubernetes-sigs/kustomize/releases/download/v${KUSTOMIZE_VERSION}/kustomize_${KUSTOMIZE_VERSION}_linux_amd64 \
&& curl -sfL -o /usr/local/bin/argocd https://github.com/argoproj/argo-cd/releases/download/v${ARGOCD_VERSION}/argocd-linux-amd64 \
&& chmod +x /usr/local/bin/kubectl /usr/local/bin/kustomize /usr/local/bin/argocd
# =======================
Base image
FROM google/cloud-sdk:297.0.1-alpine
Base image uses google / cloud-sdk: 297.0.1-alpine
Installation of general-purpose packages used in the environment
RUN apk add --no-cache fish git openssh curl
Since the base image is alpine, use apk to install the package you want to use in the development environment Here, fish, git, ssh, curl are included, but if you want to use bash, you can customize it by introducing bash instead of fish.
Settings for fish shell
COPY .config/fish/config.fish /root/.config/fish/config.fish
set normal (set_color normal)
set magenta (set_color magenta)
set yellow (set_color yellow)
set green (set_color green)
set red (set_color red)
set gray (set_color -o black)
# Fish git prompt
set __fish_git_prompt_showdirtystate 'yes'
set __fish_git_prompt_showstashstate 'yes'
set __fish_git_prompt_showuntrackedfiles 'yes'
set __fish_git_prompt_showupstream 'yes'
set __fish_git_prompt_color_branch yellow
set __fish_git_prompt_color_upstream_ahead green
set __fish_git_prompt_color_upstream_behind red
# Status Chars
set __fish_git_prompt_char_dirtystate '⚡'
set __fish_git_prompt_char_stagedstate '→'
set __fish_git_prompt_char_untrackedfiles '☡'
set __fish_git_prompt_char_stashstate '↩'
set __fish_git_prompt_char_upstream_ahead '+'
set __fish_git_prompt_char_upstream_behind '-'
function fish_prompt
set last_status $status
set_color $fish_color_cwd
printf '%s' (prompt_pwd)
set_color normal
printf '%s ' (__fish_git_prompt)
set_color normal
end
Use a fish shell as a working shell Since it is difficult to use with the default settings, copy the configuration file to change the prompt such as displaying the Git branch and place it on the container The fish configuration file is based on the following blog post. https://www.martinklepsch.org/posts/git-prompt-for-fish-shell.html
Installation of commands used with Google Cloud SDk
# ===== kubernetes resource install =====
ENV KUBECTL_VERSION 1.18.4
ENV KUSTOMIZE_VERSION 3.1.0
ENV ARGOCD_VERSION 1.5.2
RUN curl -sfL -o /usr/local/bin/kubectl https://storage.googleapis.com/kubernetes-release/release/v${KUBECTL_VERSION}/bin/linux/amd64/kubectl \
&& curl -sfL -o /usr/local/bin/kustomize https://github.com/kubernetes-sigs/kustomize/releases/download/v${KUSTOMIZE_VERSION}/kustomize_${KUSTOMIZE_VERSION}_linux_amd64 \
&& curl -sfL -o /usr/local/bin/argocd https://github.com/argoproj/argo-cd/releases/download/v${ARGOCD_VERSION}/argocd-linux-amd64 \
&& chmod +x /usr/local/bin/kubectl /usr/local/bin/kustomize /usr/local/bin/argocd
# =======================
Since I often use GKE exclusively as a GCP resource, I have Kubernetes related resources installed in the container.
devcontainer.json Configuration file when opening a container from VS Code Describe the Dockerfile to be used, the extension function when using VS Code on the container, Volume from the local environment, etc. See the official reference (https://code.visualstudio.com/docs/remote/containers#_devcontainerjson-reference) for more details on what else you can do. First give the big picture, then explain each line
devcontainer.json
{
"name": "Google Cloud SDK Remote-Container",
"build" : {
"dockerfile": "Dockerfile"
},
"settings": {
"terminal.integrated.shell.linux": "/usr/bin/fish",
},
"extensions": [
"alefragnani.bookmarks",
"mhutchie.git-graph",
"redhat.vscode-yaml",
"zainchen.json"
],
"mounts": [
"source=${localEnv:HOME}/.ssh/,target=/root/.ssh/,type=bind,consistency=cached",
"source=${localEnv:HOME}/.gitconfig,target=/root/.gitconfig,type=bind,consistency=cached",
"source=${localWorkspaceFolder}/.devcontainer/.local/share/fish/fish_history,target=/root/.local/share/fish/fish_history,type=bind,consistency=cached",
"source=${localEnv:HOME}/.config/gcloud/,target=/root/.config/gcloud/,type=bind,consistency=cached",
"source=${localEnv:HOME}/.kube/,target=/root/.kube/,type=bind,consistency=cached",
],
}
Container image to use
"build" : {
"dockerfile": "Dockerfile"
},
Specify the location of the Dockerfile As shown in the directory structure at the beginning, since it is on the same directory, it is written as "Dockerfile" as it is
Container-specific VS Code settings
"settings": {
"terminal.integrated.shell.linux": "/usr/bin/fish",
},
Describe the VS Code settings you want to set independently on the container For example, settings for Extension that are not installed locally but are installed on the container, etc. Regarding the description of settings, what is written locally is inherited on the container without writing it again on devcontainer.json Here, on the container, the terminal shell only describes using fish.
Setting the extension used by VS Code on the container environment
"extensions": [
"alefragnani.bookmarks",
"mhutchie.git-graph",
"redhat.vscode-yaml",
"zainchen.json"
],
Describe the extension you want to use in the container environment Regarding the extension, unlike the settings of settings, even if it is installed locally, those that are not written in devcontainer.json will not be installed on the container, so be careful.
Mount from local environment
"mounts": [
"source=${localEnv:HOME}/.ssh/,target=/root/.ssh/,type=bind,consistency=cached",
"source=${localEnv:HOME}/.gitconfig,target=/root/.gitconfig,type=bind,consistency=cached",
"source=${localWorkspaceFolder}/.devcontainer/.local/share/fish/fish_history,target=/root/.local/share/fish/fish_history,type=bind,consistency=cached",
"source=${localEnv:HOME}/.config/gcloud/,target=/root/.config/gcloud/,type=bind,consistency=cached",
"source=${localEnv:HOME}/.kube/,target=/root/.kube/,type=bind,consistency=cached",
],
Mount files that you want to use in your local environment or that you don't want to be erased when you restart the container "source =" specifies the local path, "target =" specifies the path on the container You can also use the environment variable "XXXX" on the local environment by writing $ {localEnv: XXXX}. Here we have 5 files and directories mounted
Java As an environment for Java, I am using an environment that includes OpenJDK + Wildfly + maven + Gradle. This Java environment will also be introduced focusing on the differences from the Google Cloud SDK environment introduced above. The whole directory structure is as follows
.
├ .devcontainer
├ devcontainer.json
├ docker-compose.yaml
├ Dockerfile
├ .m2/
├ .gradle/
├ .config/fish/config.fish
└ .local/share/fish/fish_history
docker-compose Java environment uses docker-compose instead of Dockerfile to use Docker's Network to connect to DB environment set up in a separate container First give the big picture, then explain each line
docker-compose.yaml
version: "3"
services:
jdk-wildfly-maven:
build: .
ports:
- "8080:8080"
- "9990:9990"
command: /bin/sh -c "while sleep 1000; do :; done"
volumes:
- $HOME/.ssh:/root/.ssh
- $HOME/.gitconfig:/root/.gitconfig
- .local/share/fish/fish_history:/root/.local/share/fish/fish_history
- ..:/workspace
- ./jboss_home/configuration/standalone.xml:/opt/wildfly/standalone/configuration/standalone.xml
- .m2:/root/.m2
- .gradle:/root/.gradle
networks:
- remote-container_common-network
networks:
remote-container_common-network:
external: true
Port forwarding from local environment to container environment
ports:
- "8080:8080"
- "9990:9990"
Wildfly's default ports 8080 and 9990 will be accessed on the container when the target port is accessed in the local environment.
Override container default command
command: /bin/sh -c "while sleep 1000; do :; done"
Override the default command so that the container does not stop if the default command at container startup fails or terminates The command described here is the default setting of Remote Containers when docker-compose is not used. When using docker-compose, it is necessary to write it explicitly
Mount from local environment
volumes:
- $HOME/.ssh:/root/.ssh
- $HOME/.gitconfig:/root/.gitconfig
- .local/share/fish/fish_history:/root/.local/share/fish/fish_history
- ..:/workspace
- ./jboss_home/configuration/standalone.xml:/opt/wildfly/standalone/configuration/standalone.xml
- .m2:/root/.m2
- .gradle:/root/.gradle
Mounts from local environment should be written in docker-compose.yaml instead of devcontainer.json The difference from the case of Dockerfile is that the workspace itself is explicitly specified and mounted as written as "..: / workspace". Gradle and Maven settings and repositories are mounted with ".m2: /root/.m2" and ".gradle: /root/.gradle" as settings unique to the java environment. Since this is only used in this environment, it is mounted directly on the WorkSpace instead of the user home ($ HOME). Also, regarding the Wildfly configuration file standalone.xml, the data source settings etc. may always be changed during development, and it is a problem if it is deleted every time the container is restarted. It is mounted in the form of standalone.xml: /opt/wildfly/standalone/configuration/standalone.xml "
Using docker network
networks:
- remote-container_common-network
networks:
remote-container_common-network:
external: true
Java is used as an application execution environment, so I want to connect to the DB As for DB, it starts as a container in the local environment, so create a Docker Network and use it to connect with other containers. Therefore, in order to use this environment, it is necessary to create a network in advance with the following command.
```bash
docker network create --driver bridge remote-container_common-network
```
Dockerfile Dockerfile to create OpenJDK + Wildfly + maven + Gradle environment specified in docker-compose.yaml As a base image, the JBoss official image "jboss / wildfly" is large and difficult to use, and I wanted to use an alpine-based image, so I created it based on Adoptopenjdk.
Dockerfile
FROM adoptopenjdk/openjdk11:alpine-slim
# ===== common area =====
ENV WORKSPACE_DIR "/workspace"
RUN apk add --no-cache fish git openssh curl wget tar unzip\
&& mkdir -p $WORKSPACE_DIR
COPY .config/fish/config.fish /root/.config/fish/config.fish
# =======================
# ==== wildfly install =====
ENV JBOSS_HOME "/opt/wildfly"
ENV WILDFLY_VERSION "20.0.0.Final"
RUN wget -P /opt http://download.jboss.org/wildfly/${WILDFLY_VERSION}/wildfly-${WILDFLY_VERSION}.tar.gz \
&& tar -zxvf /opt/wildfly-${WILDFLY_VERSION}.tar.gz -C /opt \
&& rm /opt/wildfly-${WILDFLY_VERSION}.tar.gz \
&& mv /opt/wildfly-${WILDFLY_VERSION} ${JBOSS_HOME} \
&& $JBOSS_HOME/bin/add-user.sh admin admin --silent
# =======================
# ==== maven install =====
ENV MAVEN_HOME "/opt/maven"
ENV MAVEN_VERSION 3.6.3
ENV PATH "$PATH:$MAVEN_HOME/bin"
ENV MAVEN_CONFIG "$HOME/.m2"
RUN curl -fsSL -o /opt/apache-maven-${MAVEN_VERSION}-bin.tar.gz http://archive.apache.org/dist/maven/maven-3/${MAVEN_VERSION}/binaries/apache-maven-${MAVEN_VERSION}-bin.tar.gz \
&& tar -zxvf /opt/apache-maven-${MAVEN_VERSION}-bin.tar.gz -C /opt \
&& rm /opt/apache-maven-${MAVEN_VERSION}-bin.tar.gz \
&& mv /opt/apache-maven-${MAVEN_VERSION} /opt/maven
# =======================
# ==== gradle install ====
ENV GRADLE_HOME "/opt/gradle"
ENV GRADLE_VERSION 6.5
ENV PATH "$PATH:$GRADLE_HOME/bin"
RUN curl -fsSL -o /opt/gradle-${GRADLE_VERSION}-bin.zip https://downloads.gradle-dn.com/distributions/gradle-${GRADLE_VERSION}-bin.zip \
&& unzip -d /opt /opt/gradle-${GRADLE_VERSION}-bin.zip \
&& rm /opt/gradle-${GRADLE_VERSION}-bin.zip \
&& mv /opt/gradle-${GRADLE_VERSION} /opt/gradle
# =======================
devcontainer.json The default settings and available settings of devcontainer.json are different depending on whether you use Dockerfile or docker-compose (for example, mount is not effective even if you write it in devcontainer.json, docker-compose Will have to be described in) See Official Reference for details.
devcontainer.json
{
"name": "JDK&Wildfly&Maven&Gradle Remote-Container",
"dockerComposeFile": "docker-compose.yaml",
"service" : "jdk-wildfly-maven",
"workspaceFolder": "/workspace",
"settings": {
"terminal.integrated.shell.linux": "/usr/bin/fish",
"java.home": "/opt/java/openjdk",
"maven.executable.preferMavenWrapper": false,
"maven.executable.path": "/opt/maven/bin",
"maven.terminal.useJavaHome": true,
"java.jdt.ls.vmargs": "-noverify -Xmx1G -XX:+UseG1GC -XX:+UseStringDeduplication -javaagent:\"/root/.vscode/extensions/gabrielbb.vscode-lombok-1.0.1/server/lombok.jar\"",
},
"extensions": [
"alefragnani.bookmarks",
"mhutchie.git-graph",
"vscjava.vscode-java-pack",
"shengchen.vscode-checkstyle",
"gabrielbb.vscode-lombok",
"naco-siren.gradle-langua"
],
"shutdownAction": "stopCompose"
}
Images and services to use
"dockerComposeFile": "docker-compose.yaml",
"service" : "jdk-wildfly-maven",
When using docker-compose, use "dockerComposeFile" and specify the location of docker-compose.yaml Also, in the case of docker-compose, there is a possibility that multiple containers are running, so specify which container to open VS Code with service.
Specify workspace folder
"workspaceFolder": "/workspace",
Unlike the case of Dockerfile, in the case of docker-compose, it is necessary to explicitly specify the location of the workspace to be mounted. In this case, you cannot specify a directory that does not exist, so create a directory such as / workspace on the Dockerfile first.
java specific settings
"settings": {
"terminal.integrated.shell.linux": "/usr/bin/fish",
"java.home": "/opt/java/openjdk",
"maven.executable.preferMavenWrapper": false,
"maven.executable.path": "/opt/maven/bin",
"maven.terminal.useJavaHome": true,
"java.jdt.ls.vmargs": "-noverify -Xmx1G -XX:+UseG1GC -XX:+UseStringDeduplication -javaagent:\"/root/.vscode/extensions/gabrielbb.vscode-lombok-1.0.1/server/lombok.jar\"",
},
"extensions": [
"alefragnani.bookmarks",
"mhutchie.git-graph",
"vscjava.vscode-java-pack",
"shengchen.vscode-checkstyle",
"gabrielbb.vscode-lombok",
"naco-siren.gradle-langua"
],
Although it is not included in VS Code of the local environment, the extension you want to use is specified in the Java environment. It also describes the contents of settings that you want to apply only on the container that supports the extension.
MySQL Create a DB to be used from Java created in the previous chapter in a container It doesn't make much sense to create this environment with Remote Containers, but to unify it, I created it with Remote Containers. There is no problem even if you simply start with docker-compose Before creating this environment to connect with other containers (Java environment), create a Docker network with the following command (If you already have it, there is no problem)
docker network create --driver bridge remote-container_common-network
The entire directory structure and configuration file are as follows
.
├ .devcontainer
│ ├ devcontainer.json
│ ├ docker-compose.yaml
│ └ my.cnf
└ db
docker-compose.yaml
version: "3"
services:
mysql:
image: mysql:5.7
environment:
MYSQL_ROOT_PASSWORD: pass
TZ: "Asia/Tokyo"
ports:
- "3306:3306"
volumes:
- ../db/data:/var/lib/mysql
- ./my.cnf:/etc/mysql/conf.d/my.cnf
networks:
- remote-container_common-network
phpmyadmin:
image: phpmyadmin/phpmyadmin
environment:
PMA_ARBITRARY: 1
ports:
- 3307:80
depends_on:
- mysql
networks:
- remote-container_common-network
networks:
remote-container_common-network:
external: true
devcontainer.json
{
"name": "MySQL Remote-Container",
"dockerComposeFile": "docker-compose.yaml",
"service" : "mysql",
"workspaceFolder": "/root",
"settings": {
"terminal.integrated.shell.linux": "/bin/bash",
},
"extensions": [],
"shutdownAction": "stopCompose"
}
This time, I'm building my own local environment, so I'm making Remote Containers settings assuming that multiple applications will be handled in one environment. In other words, the following
.
├ .devcontainer
├ application1
│ ├ .git
│ └ source code
├ application2
│ ├ .git
│ └ source code
It is better to create one Remote Containers setting for one application instead of the above configuration because it has the advantage that the development environment of that application can be managed on git and all developers can use the same environment. I think that the In other words, the following
.
├ application1
│ ├ .devcontainer
│ ├ .git
│ └ source code
├ application2
│ ├ .devcontainer
│ ├ .git
│ └ source code
However, in the case of such a management method, it is better to consult with the team and decide what to do because a war may occur if you insert the original setting of fish as introduced this time.
End the advantages and disadvantages that you thought you were using at the end
Recommended Posts