- Notifications
You must be signed in to change notification settings - Fork12.9k
Docker Quickstart
"Short" is not a joke, it's because I used many examples which is whythis text is much longer than what you need. To make it short, findthe first example that fits your needs and use it.
Docker is essentially a way to run stuff in a local sandboxedenvironment. The environment is specified by adocker image, and itsmain component is a snapshot of all files that are needed to run in, inthe form of "layers", each saved as a tar archive (and it's implementedasUnionFS).
Docker is not a VM, but often confused as one. Images arelinux-based, and therefore Docker on Windows works by installing atiny Hyper-V Linux VM to run on (but that is shared for all dockeruses, it's not starting a VM for each run).
When you run an image, the running sandbox is called acontainer.These container are based on the image which is the initial state (filesetc), and on top of that there are any changes that the currentexecution created (FS changes, running process/es, etc). When containeris done running,all of that usually disappears, making it veryconvenient to run random stuff without affecting your setup. (It ispossible to save containers, but usually they're removed after use.)
You need toinstalldocker to try thefollowing examples. The installer itself is generally well behaved andwill tell you what needs to be done to make it work (eg, turning onwindows features like hyper-v or the wsl2 backend). There are alsoinstallers for macs and for linux (the latter being a system daemonrather than a tiny vm).
Once installed, you can use thedocker
command to do stuff. It hasthe usualdocker 〈verb〉 args...
format. On windows, it works finein all forms: powershell, vscode, and even in a cmd box. The main (andpossibly the only) verb you need to know about isrun
:
docker run -it --rm node
This drops you into a runningnode
container. (Ctrl+D is thecanonical EOF-thing in unix, use it to exit the running process andtherefore the container.)
run
: start running a container for the specified image. The imagewill be pulled in on first use.-it
: interactive run (short for--interactive --tty
, the latter isa unix thing)--rm
: delete the container when done (you can drop this if you wantto keep the results, but usually you want to include it)node
: the name of the image we want to run (there aremany, enough that most random guesses for"the thing you want to try" will work)
docker run -it --rm node:12
Image names are tagged — this is similar to the above, but now I'mspecifying that I want to use the12
tag. When you don't specify atag as in the above, you get the default of:latest
.
Tags are not permanently fixed (especially not
latest
). To update atag (eg, a new node version is published), you can usedocker pull node
to update it. Similarly,node:12
is a tag that points at themost recent 12.x version.
But this is still just drops you into a runningnode
, what if you wantto do something before starting it, like installing some suspiciouspackage?
docker run -it --rm node bash
Here I added abash
at the end, overriding what thenode
image runsby default. Now I get abash
prompt, and I can do whatever I want:npm install
stuff (locally or globally),apt install
OS packages(you'll need toapt update
first to get the package directory), andevenrm /bin/*
— it's all completely safe, and everything willdisappear when the container is done.
But if you know even a little about linux, you'll recognize that this isa kind of an overkill: you start at the root of the filesystem, and astheroot
user. This could be significantly different from actual use.For example, I run into a weird new1line-aa
npm package, with novisible information about how it's working, and I want to try it as auser.
docker run -it --rm node bash$ su -l node$ npm install 1line-aa
One way to do this is to runsu -l node
in the container, which startsa new shell for thenode
user (which the node image includes). Sincethis process is started from the first one, you'll need to Ctrl+D twiceto get out of the container (or thrice if you startnode
).
docker run -it --rm -u node -w /home/node node bash
Another way to do this directly is to add:
-u node
: start as thenode
user-w /home/node
: in its home directory
So far all of these examples left nothing behind, but what if youwantto collect some of the resulting files?
docker run -it --rm -v c:\foo:/work node bash
-v c:\foo:/work
: mount thec:\foo
directory onto/work
in thecontainer
This means that in the container you cancd /work
and do whatever youwant there: since it's a mounted directory, everything will actuallyhappen in yourc:\foo
directory (which will be created if it doesn'texist). It doesn't matter that the file owner inside the container isroot
, since on a Windows host side, it's all running as your Windowsuser. This isnot the case if you're using docker on linux: in thatcase,root
in the container will create files that belong toroot
onthe host. In any case, switching to thenode
user (as done above) ispreferable.
This is a more involved example: running thefuzzer. First, clone therepository — thenode
image includesgit
so you can do it in thecontainer, but you're probably more comfortable with your usualenvironment. You'll probably use vscode or whatever... something like
c:\> cd workC:\work> git clone ...tsserverfuzzer...C:\work> cd tsserverfuzzerC:\work\tsserverfuzzer> docker run -it --rm -v %cd%:/fuzzer -w /fuzzer -u node node bash
-it --rm
: interactive, dispose after use-v %cd%:/fuzzer
: mount the current directory as/fuzzer
in thecontainer (in powershell, use$pwd
instead of%cd%
)-w /fuzzer
: and work in there-u node
: as thenode
user
node@...:/fuzzer$ npm install...node@...:/fuzzer$ npm run build...node@...:/fuzzer$ git status...node@...:/fuzzer$ node lib/Fuzzer/main.js
You can now do the usual things, evengit
commands (since the fileformat is the same — just be careful of sneaky EOL translation).
I you did all of this, thegit status
should show just a change inpackage-lock.json
, and the last execution got stuck waiting for adebugger to connect. Ctrl+C to abort it, and Ctrl+D to exit thecontainer.
docker run ...same... -p 9229:9242 node bash
It's possible to forward ports from the container to the host, and it'ssimilar to the-v
flag with the same meaning to the two sides of thecolon: here we're saying that port 9242 in the container is exposed asport 9229 on the host. Once you do that, you can skip the building(since the built files are still in the directory on your host) and gostraight to thenode
command.
... except that this won't work either. This is because the debuggerlistens on127.0.0.1:9242
(and it tells you that), which means that itonly accepts connections fromlocalhost
which is the container. We'reconnecting from what looks to the container like a different machine, sowe need to allow that. To do this, openC:\work\tsserverfuzzer\Fuzzer\main.ts
in your editor (outside thecontainer!) and change'--inspect-brk=9242'
to'--inspect-brk=0.0.0.0:9242'
(the0.0.0.0
tells it to listen toanyone).
The container sees the file modification, so you don't need to restartit, you can just runnpm build
again, and re-run.
docker run ...same... node node lib/Fuzzer/main.js
When you want to run the already-built fuzzer later, you can start itdirectly. Thenode node
looks confusing, but the first one is thename of the image, and following it is thenode
command that you wantto run in the container instead of starting an interactive repl.
docker run ...same... -e GitHubAuthenticationKey=%tok% node node lib/Fuzzer/main.js
At some point you'll find that it needs a GH key in the$GitHubAuthenticationKey
environment variable. The-e VAR=VAL
flagsets such a value, and in this case we're using a Windows%tok%
as thevalue. (And something like$env:tok
in powershell.)
Since it's running the node code directly, a Ctrl+C will stop it andexit the container immediately.
There's enough verbiage above to run it, but a few more useful bits thatare relevant in this case:
docker run ... -v %USERPROFILE%\.npmrc:/home/node/.npmrc:ro ...
You'll find that you need an npm authentication key to be able tonpm install
this thing. Assuming that you have the key in yourC:\Users\foo\.npmrc
, you can re-use your.npmrc
in the container.There are two new things here:
Container mounts don't have to be directories, you can mount a singlefile as this is doing.
An access mode can follow a second
:
, userw
(the default) forread-write orro
read-only. In this example using:ro
ensuresthat the container cannot modify the windows.npmrc
file.
C:\...> docker run -it --rm ... node bash# apt update; apt install sudo# node /work/index.js 1 3.3 3.4 false
One problem with running this code is that it requires havingsudo
,but thenode
image is based on a minimal linux so it doesn't have it.One way to do it is to fix the code to not usesudo
if it's running asroot ... but a way around it is to start the container withbash
, andrun the twoapt
commands to getsudo
installed. (In the case ofthisTypeScriptErrorDeltas
code, there is something else that isneeded: see "Privileged runs" below.)
It is obviously tedious to do this installation every time you want torun it — ignoring changing the code to not require extra packages, it ispretty easy to build an image yourself. But I'll finish the quick parthere.
A docker container is an image running in a sandboxed environment thatis restricted in several ways (like seeing its own FS and network).There are, however, cases where linux functionality is needed from thekernel — and mounting things (when you're alreadyin the container) isone such case that is normally blocked. Docker has a bunch of"capabilities" that are off by default and can be turned on if needed.In cases likeTypeScriptErrorDeltas
, where you're running knownnon-malicious code, you can just enable all of them by adding a--privileged
flag.
Thebuild
verb can be used with aDockerfile
which specifies arecipe for creating an image. For example, it's easy to make an imagethat is based on thenode
image, but has a few more os packagesinstalled, and defaults to a specific directory, user, and command torun. There's lots of examples around, but in general I'll be happy toexplain how to create any image that anyone might need.
This is a useful command to see a list of running docker containers.Usually this should be empty, but you might press some wrong key (likeCtrl+Z, which suspends a process) and end up with a stray process. Usethis to see such processes, and kill them withdocker rm -f 〈container-id〉
.
const orGUI = "Or, as long as you're a gui-dependent windows user," + "just use the docker gui...";
console.log(orGUI);
The process that gets to run on adocker run
is not the only thingthat runs. Subprocesses can run in the container, of course, but inaddition to that you can start another process in the context of arunning container. This is useful, for example, if you started acontainer as thenode
user, and you need to install some os package,but you don't want to start from scratch.
C:\> docker ps... node id ...C:\> docker exec -it 123 bash
To do this, usedocker ps
to find your container's id, then usedocker exec
to start abash
process in it. It is somewhat similartorun
except that it expects a running container id. (Or names,since you can name running containers, because why not add features.)
console.log(orGUI);
You might end up with random stuff that sticks around for whateverreason. A running or a suspeded container, stray images since youplayed with building your own image, or whatever.
docker system prune -f
This will remove any such stuffs. The-f
makes it just remove theunnecessary stuff rather than ask you for confirmation.
console.log(orGUI);
News
Debugging TypeScript
- Performance
- Performance-Tracing
- Debugging-Language-Service-in-VS-Code
- Getting-logs-from-TS-Server-in-VS-Code
- JavaScript-Language-Service-in-Visual-Studio
- Providing-Visual-Studio-Repro-Steps
Contributing to TypeScript
- Contributing to TypeScript
- TypeScript Design Goals
- Coding Guidelines
- Useful Links for TypeScript Issue Management
- Writing Good Design Proposals
- Compiler Repo Notes
- Deployment
Building Tools for TypeScript
- Architectural Overview
- Using the Compiler API
- Using the Language Service API
- Standalone Server (tsserver)
- TypeScript MSBuild In Depth
- Debugging Language Service in VS Code
- Writing a Language Service Plugin
- Docker Quickstart
FAQs
The Main Repo