Angular-cli: Provide an official Angular Cli Docker image

Created on 19 Jul 2018  路  11Comments  路  Source: angular/angular-cli

Bug Report or Feature Request (mark with an x)

- [ ] bug report -> please search issues before submitting
- [x] feature request

Description

When setting up automated Continous Integration pipelines, you normally have steps for linting, testing, building and deploying a project. There is not an official image for Angular Cli, so we have to resort to using someone else's or create our own:
https://hub.docker.com/r/alexsuch/angular-cli/
https://hub.docker.com/r/kmturley/node-angular-cli/

You already have a design doc for Docker deployments, but that is for building locally and pushing to docker hub, not building on a CI server:
https://github.com/angular/angular-cli/blob/7924e0a45545fbff3d117661388a414b7d245873/docs/design/docker-deploy.md

Desired functionality

Official Docker image pushed to Docker Hub e.g. https://hub.docker.com/r/angular/angular-cli which can be use in CI pipelines, and has versioning, so every time a new Angular version is released, a Dockerfile is created e.g.

image: angular/angular-cli
script:
  - npm run lint

Mention any other details that might be useful

People creating their own images can cause security & performance risks, and they go out-of-date as they are not connected to the original open-source github repo.

Also if you release an official Angular Cli Docker image, it will reduce bandwidth and build times for CI services who are building many sites. It's also a better developer experience :)

angulacli triage #1 feature

All 11 comments

In my particular case i'm using Docker Hub for automated builds and this would be a MAJOR improvement, mainly because of constant angular-cli updates, "skipping" installing node and cli in multi-stage builds. Thumbs Up.

Are there any plans to add this into the pipeline (sorry, had to do it)? This would simplify developers' processes dramatically.

When setting up automated Continous Integration pipelines, you normally have steps for linting, testing, building and deploying a project.

All of these steps require only the local Angular CLI, which is installed by your package manager, and can always be trigger directly by yarn ng xxx or $(npm bin)/ng xxx, say that you don't want to predefine the scripts.

There is not an official image for Angular Cli, so we have to resort to using someone else's or create our own.

When using the global CLI, mismatching between global and local CLI version would only result to uncertainty which is against the goal of integration. Or if a new version of Angular CLI published, how can you make sure the local @angular/cli dependency and global one in container are same? By running an extra validation step?

Official Docker image pushed to Docker Hub e.g. https://hub.docker.com/r/angular/angular-cli which can be use in CI pipelines, and has versioning, so every time a new Angular version is released

This would almost just misguide people, if local @angular/cli and siblings not changed, updating global @angular/cli has no real effect to your project, which would still invoke your local tools. When auto-updating the global one, people may mistakenly think the result coming from latest CLI, but that's not the case.

Also if you release an official Angular Cli Docker image, it will reduce bandwidth and build times for CI services who are building many sites

Using global CLI would only increase the bandwidth and build times, as it's not needed for any of "linting, testing, building and deploying a project" job at all.

ng-cli is used for linting, testing and building of angular apps using the commands:

    "start": "ng serve --host 0.0.0.0",
    "build": "ng build",
    "test": "ng test",
    "lint": "ng lint",
    "e2e": "ng e2e"

You are right that it's not designed to be installed globally, but I never mentioned that. Docker images are able to install node modules locally and cache the folder...

Finally to your point about mismatched versions, you are correct it could cause confusion, but if the package.json angular version is updated, then there will be a second version installed. Something that could easily be checked for and managed.

The benefits, having an image of the ng-cli installed for every version if angular would massively reduce installation and server load times on CI. Considering the linting, tests and builds happen everytime a pull request occurs.

Also consider that most libraries and frameworks have an official Docker version which is optimized and more secure, preventing things like secrets from being leaked and allowing users with different node and OS types to have a consistent testable platform.

Docker images are able to install node modules locally and cache the folder...

Your node_modules folder are not provided by Angular, but npm, yarn, pnpm, cnpm or whatever package manager. Also you can configure registry in any of those tool, others have no idea how you'll get your packages from.

Also, having a dirty cache in container will also make build result unreliable, there're thousands of GitHub issues or StackOverflow question end with npm cache clean --force, including Angular CLI ones.

Also consider that most libraries and frameworks have an official Docker version which is optimized and more secure

This would only happen when additional binary is needed, but now you need only npm binary, then you should ask npm to provide an official image, same for yarn, pnpm, cnpm or any possible tools.

Just got those who visit this issue, there is one more image https://hub.docker.com/r/trion/ng-cli/

Discussed this with the team today and our feelings are that adding an Angular CLI docker image would not significantly improve CI performance or developer experience.

Firstly, using a base Docker image with the CLI installed does not really improve performance as a global install of the CLI will always defer to the local one (to avoid version mismatch issues). As a result, a build will still need to install a local version of the CLI based on package.json version numbers and will use that to actually build the app. Having a global install already present does not improve this performance.

Secondly, the global CLI install is really only useful as developer convenience. Developers typically prefer using ng new or ng generate to bootstrap new code because it is the easiest way to do so. However most of the project build/test/serve functionality is typically supported via NPM scripts, such as npm run build or npm start. NPM already has mechanisms for deferring to locally installed modules like the Angular CLI for these scripts. Since the global install of ng only really serves convenience for developers, there is no need for it in a CI system. npm install should provide all the tools necessary to build and run your application. Relying on a globally installed tool from the environment only complicates the process.

Our recommendation is to forgo the global install of the CLI and simply use the local install via npm run build and the other NPM scripts. This is much simpler to set up, just as if not more performant, and does not introduce skew.

I filed https://github.com/angular/angular/issues/37442 as a documentation issue so we can more clearly and officially describe the best practices for working with Docker for CI and deployments.

Ok! looking forward to a guide which recommends best practices for use of Angular, Docker and CI pipelines. When you start running 100's of Angular builds a day, you start to get into the use-cases mentioned.

@kmturley We've implemented the following approach to reducing build times with Angular.

Starting with a multi-stage Dockerfile:

FROM node:12.2.0 as build
WORKDIR /app
COPY package.json /app/package.json
COPY package-lock.json /app/package-lock.json

RUN npm ci
COPY . /app

RUN ng build --prod

FROM nginx:1.17-alpine
COPY --from=build /app/dist /usr/share/nginx/html

This is all straight forward. Then, when we build, we actually build and tag each stage separately:

docker build --target=build -t app:build .
docker build --cache-from app:build --tag app:$BRANCH_NAME
docker push app

Building each item separately allows us to then push both the app:build and app:1.0.0 tags to the registry. The next build does a pull, then use the cache from each one:

docker pull app:build
docker pull app:$BRANCH_NAME
docker build --target=build --cache-from app:build -t app:build .
docker build --cache-from app:build --cache-from app:$BRANCH_NAME -t app:$BRANCH_NAME .
docker push app

Keeping the temporary app:build tag in the registry speeds up the builds significantly, as it can continue to use the cache so long as the package.json and package-lock.json files are the same. Continually overwriting the app:build tag, even on branches, is fine for us, and we suffer the slightly increased build times when these files change on branches, or on master and we have older branches.

Agree with @dgp1130. The mechanism it's already clear and works, it would be a mistake to change it in favor of a container pseudo-optimization.

When I asked for an image optimization, my current CI pipeline was Docker Hub. The resources assigned for Docker Hub are very low and defficient. My Dockerfile include npm ci, cache clean-ups & more... build time was around 23-25 minutes. Not very performant.

When we moved to GitHub Actions things changed drastically without changing anything. Build times went down to 4-5 minutes. Better numbers to say the least.

Considering the current mechanisms and architecture, it all depends on the resources assigned to the build process. My local build times are around 3-4 minutes, very aligned with the GitHub Actions times, and it's a pretty decent time compared with the 25 minutes of Docker Hub.

This issue has been automatically locked due to inactivity.
Please file a new issue if you are encountering a similar or related problem.

Read more about our automatic conversation locking policy.

_This action has been performed automatically by a bot._

Was this page helpful?
0 / 5 - 0 ratings