open vscode server gitpod development docker deployment
| | | | |

Open VSCode Server Offline Deployment for NodeJs Development

UPDATE 1:

open-vscode server now does a lot of online checks that prevent a good amount of functionalities from working offline. there is another project called code-server that does not have that issue.

I will be creating a blog post for it sometime soon on how to configure it for an offline environment. Though generally, it’s similar to this one, but with different directories locations.

Introduction

building open vscode server image

Working in offline environments is really difficult nowadays with almost everything connected to the internet. This is especially true with development, whether it is with Node or Python as they most probably require an online package repository to download their packages from.

On top of that, you might be restricted from installing executables, and you will be stuck with windows default applications like notepad to do your coding. This is not an ideal environment for a developer.

The solution to work around these limitations is the newly introduced openvscode-server by gitpod.

Pre-Requisites

Now, this solution will highly depend on docker. So on both of our offline and online environments, we will need:

Solution Flow

We need to be solving 3 main problems when developing in an offline environment with vscode.

  • vscode extensions
  • Language Runtime Environment (NodeJs)
  • Dependencies (NPM/Yarn)

In order to solve those problems, we will need to follow this flow:

offline development environment flow

Before going into the solution, we need to understand how it flows from a theoretical standpoint to understand how we are solving each problem.

vscode extensions

Since we won’t have any access to vscode’s marketplace in our offline environment, then we will need to install them in an online environment first and copy those extensions to a customized docker image.

lanuage compiler/runtime

For NodeJs development, we will need to install node, npm, and yarn.

dependencies

We will have to install the dependencies of our node project during the process of creating our docker image.

Deploy openvscode with docker

In our online environment, we will run an openvscode-server docker container first

docker run -it --init -p 3000:3000 gitpod/openvscode-server:1.63.2

Make sure to specify the version you are deploying, as this is important for the vscode extensions compatibility. As of writing this blog post, 1.63.2 is the latest version. To check the more recent versions in the future, you can visit the tags section of the image on dockerhub.

once you have it deployed, you need to check the container’s logs to get the security token. Running the earlier command will print out that log into your shell.

open vscode token gitpod

Once we have it copied, we will access openvscode server with the port we exposed, and passing the token as a URL parameter:

http://localhost:3000/?tkn=YOUR_TOKEN_HERE

And we can now view our web-based self-hosted vs code!

gitpod vscode server deployed!

Install vscode extensions

The next part is to install the extensions we usually use with vscode. This step is up to you as each person has their own preferences.

The thing you should take note of here is that we are using a specific version of openvscode, and the extensions we are going to install will be mainly compatible to that version. Make sure that when you install more extensions in the future that you use the same version of openvscode to ensure the extensions that you downloaded will work.

A note about gitpod’s openvscode-server’s extensions

You may have noticed that the extensions marketplace looked odd, with the ratings being less than how you’d usually remember them to be. This is because gitpod used open vsx registry as their marketplace. code-server, a project similar to gitpod’s openvscode-server details the reasoning behind it. Long story short, it’s due to Microsoft’s Term of Service.

Marketplace Offerings are intended for use only with Visual Studio Products and Services, and you may only install and use Marketplace Offerings with Visual Studio Products and Services.

You can also use the extensions from the official marketplace with gitpod’s openvscode-server. But what you need to make sure of is the version of vscode is the same one as gitpo’s openvscode-server.

Copy The installed vscode extensions to the host

the plugins that we installed will be in this directory in our container:

/home/workspace/.vscode-server/extensions

what we will need to do is to copy those extensions from our docker container to our host.

first, we need to find the container id

docker ps

once we do, we will copy the extensions to our host.

docker cp containerId:/home/workspace/.vscode-remote/extensions .

and now in our host, we will have the extensions directory that has all of the extensions that we installed.

Create a customized Open VSCode server Image for offline deployment

Now in a single directory, we will have the extensions that we just copied from the container, the Node Project we want to move to the offline environment, and we will create a dockerfile.

For the project, I created a simple Typescript Express app that gives me a simple HTML “hello” page:

import express from 'express';
const server = express();

server.get('/', (req, res) => {
  return res.send('<h1>hello</h1>');
});

server.listen('3000', () => {
  console.log('🚀 server started at port 3000');
});

in the dockerfile, we will have the following configuration:

FROM gitpod/openvscode-server:1.62.3
# copy the extensions we installed to the image
COPY  --chown=openvscode-server:openvscode-server  ./extensions/ /home/workspace/.vscode-remote/extensions/
COPY --chown=openvscode-server:openvscode-server ./my-project/ /home/workspace/repos/my-project/
RUN sudo apt update
RUN sudo apt install -y curl
# update the packages list
RUN sudo curl -fsSL https://deb.nodesource.com/setup_16.x | sudo bash -
# install the packages
RUN sudo apt install -y nodejs
RUN sudo npm install -g yarn
# install the dependencies of our project
WORKDIR /home/workspace/repos/my-project
RUN yarn
# run it in another port because react uses port 3000 by default
ENTRYPOINT exec ${OPENVSCODE_SERVER_ROOT}/server.sh --port 9876 "${@}" --

Dockerfile Explanation

let us walk through what we are doing with each part.

FROM gitpod/openvscode-server:1.62.3

means we are using gitpod/openvscode-server:1.62.3 as our base for this image, and we will build on top of it.

COPY  --chown=openvscode-server:openvscode-server  ./extensions/ /home/workspace/.vscode-remote/extensions/

here, we are copying the extensions directory from our host to the new image’s extensions path. It’s the same path that we got the installated extensions from our running instance.

we added the --chown=openvscode-server:openvscode-server argument to make sure that the ownership is given to the user openvscode-server, which is the user that uses openvscode-server. if the extensions directory (or its contents) changed to another user (like root), then openvscode-server will fail to load the extensions.

COPY --chown=openvscode-server:openvscode-server ./my-project/ /home/workspace/repos/my-project/

and here, we are copying the node project directory to the image.

Our base image gitpod/openvscode-server:1.62.3 already has /home/workspace directory, and with our COPY command, we are creating the directories repo and my-project, then copying our host my-project directory to our image.

RUN sudo apt update

openvscode-server image is based on ubuntu:18.04 image. With that in mind, it means we can install our packages through the apt command.

Before we do so, we will need to update our repository list first, since the ubuntu image is as bare bones as possible, and it wouldn’t have a list of the most recent available versions of the packages.

RUN sudo apt install -y curl

we’ll be installing curl, as we need that to install NodeJs.

RUN sudo curl -fsSL <https://deb.nodesource.com/setup_16.x> | sudo bash -

This command will let us install NodeJs v16’s repository into our apt sources. We are doing this because the apt repository is not updated to have the most recent versions of NodeJs.

Note that we are installing v16 in this tutorial, which is LTS as of writing this Post. This may change in the future, and you can find which repository to add from here.

RUN sudo apt install -y nodejs
RUN sudo npm install -g yarn

these commands should be self-explanatory for a NodeJs developer. We are installing NodeJs, NPM and Yarn. when installing NodeJs from the repository that we added, it will install NPM with it.

WORKDIR /home/workspace/repos/my-project
RUN yarn

we can then change our working directory to where we copied our project, and install the dependencies. You’d be using npm install if you were using NPM here. WORKDIR is somewhat similar to cd.

ENTRYPOINT exec ${OPENVSCODE_SERVER_ROOT}/server.sh --port 9876 "${@}" --

Finally, we are modifying the original ENTRYPOINT to change the port openvscode-server will run on in the container.

This is because 3000 is a common port for React for example, and rather than having to change React’s listening port, we will change openvscode-server’s port instead. We are doing it this way because we want the back and forth transition between our online and offline environments to be “seamless”. The goal here is to give a similar experience to when developing in an online environment, without the need to re-configure our project.

Creating the Image

with our dockerfile ready, we will type the following command at the same location of the dockerfile:

docker build . -t my_organization/openvscode-server:1.62.3

and this will build our image with the tag we just gave it.

Moving the Docker Image to an Offline Environment

Save the Docker Image

to save the docker image, we can use following command:

docker save my_organization/openvscode-server:1.62.3 -o openvscode-server-1-62-3.tar

after we get the image exported to the tar file, we will then copy it to our offline environment

Loading the docker image

in our offline environment, we will load our docker image with this command:

docker load -i openvscode-server-1-62-3.tar

Running the Container in the Offline Environment

From there, we can finally get our container started with the image that we created, and it should work right away.

we will create a docker-compose.yml file:

version: '3'
services:
  code:
    image: my_organization/openvscode-server:1.62.3
    volumes:
      - workspace:/home/workspace
    ports:
      - 3000:3000 # our express app
      - 9876:9876 # our openvscode-server

volumes:
  workspace:

and run:

docker-compose up -d

since we are using the -d argument, we will not be able to see the logs of the container. To do so, we will first get the ID of the container:

docker ps

then inspect the logs:

docker logs CONTAINER_ID

and that’s it! our offline development environment should be working properly from here!

we can test out our node express app, and it will be able to run it properly!

starting our express app in gitpod open vscode server offline

we can then visit the page from the port we routed it to, and we will see our “hello” page there as well.

Limitations

This solution is to get you up and ready for offline development quickly. Though, am sure you can tell that there are a few limitations.

  • No offline package repositories for NPM/Yran
    • This means that removing /node_modules for a node project is dangerous, and we won’t be able to restore it. Unless we deploy a new container and copy it over.
    • We can’t really install additional packages in the offline environment
  • The Exposed Ports will quickly conflict and/or get out of hand if we have multiple developers.
    • A developer running react would usually use port 3000. We can always map different ports for each developer, but this can get tedious as they might need more ports.

These limitations luckily have solutions for them, and we will be discussing them later in the future.

Conclusion

Offline environments are a huge obstacle for developers, and overcoming them can be a daunting task. The power of docker and gitpod’s openvscode have greatly simplified preparing a development environment very quickly.

Sing up to get an email notification when new content is published

2 Comments

  1. Thank you very much. It was very helpful. It took a while but after a few missteps I got it working. Is ‘home/workspace/’ a Linux directory? I did it on a Mac. It worked but opening a project was a little difficult so I cloned one from Github to get started. Also, don’t you need to add ‘-f’ and the filename in the docker build step? I used this: “docker build . -f openserver.docker.txt -t openvscode-server:1.62.3” (in the same directory where the extensions were saved.)

    1. Hey Darren!

      I’m glad that it helped!

      `home/workspace` is indeed a Linux directory. open vscode server is built on top of an Ubuntu container.

      the `-f` argument is only needed when you want to target a specific file for docker to read from to create an image.
      By default, `docker build` will look for a file named `dockerfile` to get the build configuration from.
      the `.` in `docker build .` means “look for the `dockerfile` file here, in where I just ran the command”.

      `-f` can be used if you are using a file that is not named `dockerfile`, like in your case. It’s useful when you have multiple files with docker images configurations, and you’d want to use a specific one.

Leave a Reply

Your email address will not be published. Required fields are marked *