I want to create a simple Progressive Web Application (PWA) user registration dialog, which runs on mobile devices, accepts user data and saves them to some backend.
I chose Ionic 2 (ignoring its capabilities to create native apps), because it’s based on Angular 2. It’s like sliced bread. And it uses TypeScript as its (preferred) language. If you’re new to Angular (as I am), head over to Code School’s Accellerating through Angular 2.
Refusing to infect my MacBook with all sorts of beginner’s (and beta) garbage, I chose to confine my developer environment within a Docker container, avoiding both homebrew and the irreversible native installer as well.
This will give you a virtual environment to take with you, hand over to colleagues, or even publish for anyone to start using within a couple of minutes.
This is not a tutorial. You’ll have to visit the links on your own in order to grasp, what and why you’re doing. I loosely followed Heitor’s recipe at Getting Started with Docker for the Node.js Developer, skipping Express in favor of Ionic 2 and ignoring any deprecated (e.g. Boot2Docker) stuff, instead immediately heading over to …
▶︎ Install Docker for Mac, outlined at Getting started: It’s just dragging the Docker app to your applications folder. Windows users should instead head over to Docker for Windows, Linux users to Install Docker Engine on Linux.
Then open Terminal and enter
docker run hello-world
in order to verify your installation and you’ve both, downloaded a public Docker image to your computer, instantiated a container and run a Hello World app.
Sit back for a moment and start figuring out: Docker is like introducing dependency injection into lightweight virtual machines, creating snapshots (i.e. containers) and exporting them as new VMs (i.e. Docker images). And it has an infrastructure to share complete solutions.
▶︎ Consider installing Kitematic, an optional GUI for managing your Docker containers. It’s neither required nor terribly useful, but handy for a Docker novice to visually explore what Docker is all about:
▶︎ Install Ubuntu and Node.js. There are a one-stop Debian based Docker images for Node.js, but I followed Heitor’s path, that more closely mimics a real Linux installation and manually installs any required stuff step-by-step.
I’ll later present an automated way to configure your environment. Skip to Introducing Dockerfiles and mounted volumes.
docker pull ubuntu docker run ubuntu /bin/echo 'Hello World' docker run -i -t ubuntu
You’ll now be sitting in front of an Ubuntu shell. Try
ls -la and install Node.js and npm:
ls -la apt-get update # As of 03-jul-16: Ionic is not yet ready for Node.js 6 # see https://github.com/driftyco/ionic-cli/issues/960 apt-get install curl curl -sL https://deb.nodesource.com/setup_5.x | bash - apt-get install nodejs node -v
npm install -g ionic@beta exit
Now save the container as a new image:
# Get your CONTAINER_ID docker ps -a # Save your container as a new image docker commit -a 'YOUR_NAME <YOUR@EMAIL>' -m 'ionic2 devjump' \ CONTAINER_ID my-ionic2:0.1 docker tag my-ionic2:0.1 my-ionic2:latest
And immediately shell a new container running your Ionic 2 installation:
docker run -i -t -p 8100:8100 -p 35729:35729 my-ionic2
Create and start your first Ionic 2 app:
ionic start cutePuppyPics sidemenu --v2 --ts ### --ts = TypeScript cd cutePuppyPics ionic serve --all ### without the --all Safari wouldn't connect to Ionic
Now head over to Safari or Chrome and open http://localhost:8100:
And on the iPad (serving as a personal LTE hotspot):
There’s some confusion about whether Docker for Mac is able to publish container ports to networks other than localhost. Using Docker for Mac 1.12.0-rc2-beta17 (build: 9779) and after having added a permissive rule to my Little Snitch in order to account for com.docker.slirp, everything appeared to be fine.
Introducing Dockerfiles and mounted volumes
Full stop! You might be tempted to start designing your app right now – but you shouldn’t! The source for your app is still within a Docker container. Once a container is gone, your sources will be gone as well.
If anything were missing or had to be changed within your Docker image, most probably you would have to start all over, tediously copy-pasting and running all statements again and and again.
▶︎ Create a new Dockerfile, i.e. from my Gisthub. NB: In favor of the automated build at Docker Hub, this example Dockerfile will not receive any further commits.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
|# No thrills Ionic 2 developer environment|
|# See https://blog.saddey.net/2016/07/03/jump-start-into-angular-2-and-ionic-2|
|MAINTAINER Reiner Saddey <email@example.com>|
|LABEL Description="Interactive Ionic 2 Framework example using volume /projects as the root for your app directories"|
|RUN apt-get update|
|RUN apt-get install -y -q \|
|# As of 03-jul-16: Ionic is not yet ready for Node.js 6, see https://github.com/driftyco/ionic-cli/issues/960|
|# RUN curl -sL https://deb.nodesource.com/setup_6.x | bash –|
|RUN curl -sL https://deb.nodesource.com/setup_5.x | bash –|
|# nodejs includes matching npm as well|
|RUN apt-get install -y -q \|
|&& apt-get -y autoclean \|
|&& rm -rf /var/lib/apt/lists/*|
|# As of 03-jul-16: You have been warned, DO NOT push this button: RUN npm update -g npm|
|# https://github.com/npm/npm/issues/9863 Reinstalling npm v3 fails on Docker|
|RUN npm install -g -y ionic@beta|
|RUN echo '1. Run ineractively and map the /projects volume to your host, e.g. docker run -it -v /Users/<host_path>:/projects <image>' > /readme.txt|
|RUN echo '2. ionic start myFirstIonic2App sidemenu –v2 –ts ### –ts selects TypeScript' >> /readme.txt|
|RUN echo '3. cd myFirstIonic2App' >> /readme.txt|
|RUN echo '4. ionic serve –all' >> /readme.txt|
|RUN echo 'cd /projects' > /start.sh|
|RUN echo 'cat /readme.txt' >> /start.sh|
|CMD bash -C '/start.sh';'bash'|
|EXPOSE 8100 35729|
|# 20-aug-16: Do NOT use VOLUME statement as it may result in numerous|
|# orphaned volumes when innocent users or apps just run|
|# docker run –rm … bash|
|# VOLUME /projects|
Next here is another shortcut: Instead of having to build the image yourself, skip to Let Docker Hub create your Docker image.
▶︎ Create a new Docker image
NB: We’ll pipe the bare Dockerfile into the build in order to prevent any context, i.e. stray files to be included as well.
docker build -t my-ionic2:0.2 -t my-ionic2:latest - > Dockerfile
If you’re too lazy to create the Dockerfile yourself, you can use mine (the one shown above) as-is instead:
docker build -t my-ionic2:0.2 \ -t my-ionic2:latest https://git.io/vKf3j
▶︎ Now run this image in new container, mounting /projects from your hosts file system and opening standard ports for Ionic development. NB: Always use absolute host paths as shown in this example. Otherwise Docker might misinterpret them as volume names. See Manage data in containers. With Docker for Mac, you may not be able to share arbitrary host paths: “You can share files in /Users, /Volumes, /private, and /tmp directly.”.
docker run --name my-ionic2 -it -p 8100:8100 -p 35729:35729 \ -v /Users/rsaddey/Documents/Dockers/projects/:/projects \ my-ionic2
In order to avoid containers piling up or having to remove them manually, you may pass
--rm to remove the container once its shell has exited. I prefer to re-use the same container instead, as long as it’s not kaputt:
▶︎ Re-use container, preserving ports, mounted /projects and your shell history
docker start -ai my-ionic2
Let Docker Hub create your Docker image
Once you’ve prepared a Dockerfile, you may chose to host it at Github (or Bitbucket) and have Docker Hub run the build, e.g. on every push. See Automated Builds on Docker Hub.
- Create a Github repo for the Dockerfile, e.g. https://github.com/rsaddey/jump-ionic2
- Create an automated build on Docker Hub, e.g. https://hub.docker.com/r/rsaddey/jump-ionic2/
Then use the image(s) to create your Docker containers:
docker run --name jump-ionic2 -it -p 8100:8100 -p 35729:35729 \ -v /Users/rsaddey/Documents/Dockers/projects/:/projects \ rsaddey/jump-ionic2
Again, once the container has stopped, you may continue where you left off:
docker start -ai jump-ionic2
and resume using it …
ionic start myFirstIonic2App sidemenu --v2 --ts cd myFirstIonic2App ionic serve --all
… by navigating to http://localhost:8100/ on your host:
Need a second shell to the same container?
docker exec -it jump-ionic2 bash