Now, let's configure some Docker scripts that you can use to automated the building, testing, and publishing of your container. I have developed a set of scripts called npm Scripts for Docker that work on Windows 10 and macOS. You can get the latest version of these scripts at bit.ly/npmScriptsForDocker:
- Sign up for a Docker Hub account on https://hub.docker.com/
- Create a public (free) repository for your application
- Update package.json to add a new config property with the following configuration properties:
package.json ... "config": {
"imageRepo": "[namespace]/[repository]",
"imageName": "custom_app_name",
"imagePort": "0000"
}, ...
The namespace will be your DockerHub username. You will be defining what your repository is called during creation. An example image repository variable should look like duluca/localcast-weather. The image name is for easy identification of your container, while using Docker commands such as docker ps. I will call mine just localcast-weather. The port will define which port should be used to expose your application from inside the container. Since we use 5000 for development, pick a different one, like 8080.
- Add Docker scripts to package.json by copy-pasting the scripts from bit.ly/npmScriptsForDocker. Here's an annotated version of the scripts that explains each function.
Note that with npm scripts, the pre and post keywords are used to execute helper scripts, respectively, before or after the execution of a given script and scripts are intentionally broken into smaller pieces to make it easier to read and maintain them:
package.json
... "scripts": {
... "predocker:build": "npm run build",
"docker:build": "cross-conf-env docker image build . -t $npm_package_config_imageRepo:$npm_package_version",
"postdocker:build": "npm run docker:tag",
...
npm run docker:build will build your Angular application in pre, then build the Docker image using the docker image build command and tag the image with a version number in post:
package.json
...
"docker:tag": " cross-conf-env docker image tag $npm_package_config_imageRepo:$npm_package_version $npm_package_config_imageRepo:latest",
...
npm run docker:tag will tag an already built Docker image using the version number from the version property in package.json and the latest tag:
package.json
...
"docker:run": "run-s -c docker:clean docker:runHelper",
"docker:runHelper": "cross-conf-env docker run -e NODE_ENV=local --name $npm_package_config_imageName -d -p $npm_package_config_imagePort:3000 $npm_package_config_imageRepo",
...
npm run docker:run will remove any existing, prior version of an image and run the already built image using the docker run command. Note that the imagePort property is used as the external port of the Docker image, which is mapped to the internal port of the image that the Node.js server listens to, port 3000:
package.json
...
"predocker:publish": "echo Attention! Ensure `docker login` is correct.",
"docker:publish": "cross-conf-env docker image push $npm_package_config_imageRepo:$npm_package_version",
"postdocker:publish": "cross-conf-env docker image push $npm_package_config_imageRepo:latest",
...
npm run docker:publish will publish a built image to the configured repository, in this case, Docker Hub, using the docker image push command. First, the versioned image is published, followed by one tagged with latest in post:
package.json
...
"docker:clean": "cross-conf-env docker rm -f $npm_package_config_imageName",
...
npm run docker:clean will remove a previously built version of the image from your system, using the docker rm -f command:
package.json
...
"docker:taillogs": "cross-conf-env docker logs -f $npm_package_config_imageName",
...
npm run docker:taillogs will display the internal console logs of a running Docker instance using the docker log -f command, a very useful tool when debugging your Docker instance:
package.json
...
"docker:open:win": "echo Trying to launch on Windows && timeout 2 && start http://localhost:%npm_package_config_imagePort%",
"docker:open:mac": "echo Trying to launch on MacOS && sleep 2 && URL=http://localhost:$npm_package_config_imagePort && open $URL",
...
npm run docker:open:win or npm run docker:open:mac will wait for 2 seconds and then launch the browser with the correct URL to your application using the imagePort property:
package.json
...
"predocker:debug": "run-s docker:build docker:run",
"docker:debug": "run-s -cs docker:open:win docker:open:mac docker:taillogs" },
...
npm run docker:debug will build your image and run an instance of it in pre, open the browser, and then start displaying the internal logs of the container.
- Install two development dependencies that are needed to ensure cross-platform functionality of the scripts:
$ npm i -D cross-conf-env npm-run-all
- Customize the pre-build script to execute unit and e2e tests before building the image:
package.json "predocker:build": "npm run build -- --prod --output-path dist && npm test -- --watch=false && npm run e2e",
1. Development time payload of ~2.5 MB is optimized down to ~73kb or less
2. The configuration items defined in src/environments/environment.prod.ts is used at runtime
- Update src/environments/environment.prod.ts to look like using your own appId from OpenWeather:
export const environment = {
production: true,
appId: '01ffxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
baseUrl: 'https://',
}
- Create a new file named Dockerfile with no file-extensions
- Implement the Dockerfile, as shown:
Dockerfile FROM duluca/minimal-node-web-server:8.11.1 WORKDIR /usr/src/app COPY dist public
- Execute npm run predocker:build to ensure that your application changes have been successful
- Execute npm run docker:build to ensure that your image builds successfully
While you can run any of the provided scripts individually, you really only need to remember two of them going forward:
- npm run docker:debug will test, build, tag, run, tail and launch your containerize app in a new browser window for testing
- npm run docker:publish will publish the image you just built and test to the online Docker repository
- Execute docker:debug in your terminal:
$ npm run docker:debug
A successful docker:debug run should result in a new in-focus browser window with your application and the server logs being tailed in the terminal, as follows:
Current Environment: local.
Server listening on port 3000 inside the container
Attenion: To access server, use http://localhost:EXTERNAL_PORT
EXTERNAL_PORT is specified with 'docker run -p EXTERNAL_PORT:3000'. See 'package.json->imagePort' for th
e default port.
GET / 304 12.402 ms - -
GET /styles.d41d8cd98f00b204e980.bundle.css 304 1.280 ms - -
GET /inline.202587da3544bd761c81.bundle.js 304 11.117 ms - -
GET /polyfills.67d068662b88f84493d2.bundle.js 304 9.269 ms - -
GET /vendor.c0dc0caeb147ad273979.bundle.js 304 2.588 ms - -
GET /main.9e7f6c5fdb72bb69bb94.bundle.js 304 3.712 ms - -
- Execute docker:publish in your terminal:
$ npm run docker:publish
You should observe a successful run in the Terminal window like this:
The push refers to a repository [docker.io/duluca/localcast-weather]
60f66aaaaa50: Pushed
...
latest: digest: sha256:b680970d76769cf12cc48f37391d8a542fe226b66d9a6f8a7ac81ad77be4f58b size: 2827
Let's look into an easier way to interact with Docker next.