A few days ago we got a new NAV Development Preview from Microsoft.
As Waldo already explained on his blog, a lot has changed this time. Well, I’m not going to repeat after him. I got the opportunity to play for a couple of weeks with it, and I wanted to share some tips and tricks with you. We are all new docker images, the new type of deployment. I do not know all details of docker, that’s for sure. If you have the chance, I recommend to join the sessions about Docker at Directions US, Directions EMEA or NAV Techdays. And I can definitely recommend to read the blog of Tobias Fenster for more in depth information around Dynamics NAV and Docker.
Docker image vs container
Let’s first get used to the difference of a docker image and container. A docker image is a prepared blueprint of an application. It is a complete filesystem that contains all files and settings needed to run an application. In the case of Dynamics NAV, it contains the NAV Server Tier, a SQL Server Express instance, the NAV Web Client, well… just everything that’s needed for a complete NAV environment.
The docker image on itself doesn’t do anything. Like I said, it is a blueprint. To get it up and running, you start a new container based on the image. The container is a stand-alone environment based on the image. Any changes in that container do not reflect into the image, they stay inside the container. In other words, a docker container is a running instance of a docker image. The docker image is immutable, all changes are captured inside the container.
On top of that, it is possible to run multiple containers, based on the same image. Or to run multiple containes, based on different images. The containers are isolated, they do not interfere with each other. Think about that for a minute. You have exactly the same application, running in separated and isolated environments all on the same host computer. No problems with multiple versions, languages or whatever.
The host computer
Docker containers run on a host computer. In the case of the NAV Developer Preview that host is an Azure Virtual Machine. It is also possible to run it on a local Hyper-V machine or even on your local Windows 10 environment. In this post, we will focus at the Azure VM host that is created with the link provided by Microsoft: http://aka.ms/navdeveloperpreview.
Dealing with containers
There are a number of scenario’s that I came across and I thought it would helpful to share them:
- How to see a list of containers
- How to stop a running container
- How to start a stopped container
- How to see the log of a container
- How to remove a container
- How to see a list of available images
- How to spin up a new container
- How to connect to the container with VS Code
All of these scenario’s can be handled using the docker command. I’m using the PowerShell editor to deal with them. And it’s perfectly possible to store your commands in PowerShell scripts for later usage. However, keep in mind that the docker command is not a PowerShell cmdlet. It is a Windows executable and also available from the command prompt. For that reason, the output does not behave exactly the same as with PowerShell cmdlets.
How to see a list of containers
Let’s start with the most easiest one, a list of containers.
The command for that is
docker ps
The output looks like this:
As you can see the output looks distorted. There is not so much you can do about that. However, there is an option to specify which columns you want to see. For example this command:
docker ps --format "table {{.ID}}\t{{.Image}}\t{{.Status}}"
Has this output:
The command docker ps only displays running containers. To see all containers, including the stopped ones, use the -a parameter:
docker ps -a
You see what I mean with distorted output? Luckily the parameters can be combined:
docker ps -a --format "table {{.ID}}\t{{.Image}}\t{{.Status}}"
The CONTAINER ID is important. We are going to use that on further commands that deal with containers. Luckily, we don’t need the whole ID. As a matter of fact, what we see here as the ID is not the complete ID either. The ID is actually a whole bit longer. However, when it comes to ID’s with docker, we only need the first few characters, only those characters that makes the ID unique. In this case 6e and 2d are already enough to uniquely identify the containers.
Or, if you prefer, you can use the name of the container. When you start a container, you can specify a name. If you don’t, then docker will assign a name. Here I have included the name in the formatted output.
docker ps -a --format "table {{.ID}}\t{{.Image}}\t{{.Status}}\t{{.Names}}"
In this list, the name generated by docker is gifted_tesla. I really didn’t invent that!
Anyway, every time I use the name gifted_tesla below, you should replace it with the container name or id of the container you are working with.
How to stop a running container
Ok, we have a container running. How to stop it? Let’s stop the container with name gifted_tesla in our list of running containers.
docker stop gifted_tesla
Remember, you can also use the container id:
docker stop 6e
That looks a little bit more technical and mysterious, doesn’t it? If that is more your cup of tea, feel free to use the container id instead of the name.
Now we have a running container and a stopped container:
Please note, there is also a command docker kill. The difference is that the stop command tries to gracefully stop the container while the kill command stops it almost instantly.
How to start a stopped container
I guess you can almost guess the command…
docker start gifted_tesla
Of course you should wait until the STATUS says healthy, before you start using the container.
Now, this command is also needed in case you have stopped and started the host (the Azure VM). If you need to start the navserver after a reboot, simply use this command:
docker start navserver
How to see the log of a container
Every container has a log. Output from the container, like message during startup or during the execution, will be logged. To show the log:
docker logs gifted_tesla
So, in case you lost information like URL’s or generated password, no worries, just read the log.
How to remove a container
Ok, let’s say that a container has done its duty, and now you want to completely remove it. You know how to stop it. But then the container remains in the list of stopped containers.
The command to completely remove the stopped container is:
docker container rm gifted_tesla
So… the tesla is history now… 😉
Please be careful with this command: it removes the container without an option to recover it!
How to see a list of available images
To start a new container, you need to specify the image. So let’s first have a look how you can get the available images on the system.
docker images
Every image has a repository and tag that together uniquely identify the image. And of course the image id is also a unique identifier.
The NAV Developer Preview September Update comes with the dynamics-nav image, tagged with devpreview-finus. There is some logic behind these names that I will not touch here, since the repository itself, navdocker.azurecr.io is currently secured with a password. So at this stage, it doesn’t make sense to go into details about tag names, I leave that to Microsoft to disclose at their moment of choice.
How to spin up a new container
There can be several reasons to spin up a new container. E.g. you screwed up or lost the existing container. Or you want to run an extra instance to test with, or to test another app.
Now this is a more complex scenario, and I will certainly not be able to cover all different scenario’s. Let’s start with the basic command docker run:
docker run -e ACCEPT_EULA=Y navdocker.azurecr.io/dynamics-nav:devpreview-finus
The parameter -e puts the environment variable ACCEPT_EULA inside the container with value = Y. Without accepting the End User License Agreement, the Dynamics NAV container will fail to start.
The docker run command accepts a complete image tag. In this case we use navdocker.azurecr.io/dynamics-nav:devpreview-finus. You recognize that as the repository name and tag from the previous screenprint. Please note the colon between the repository name and the tag.
Instead of this complete image name, we could also go for the more mysterious, but shorter, usage of the image id:
docker run -e ACCEPT_EULA=Y 22
In both case, the output looks like this:
The output stops here and doesn’t return to the PowerShell prompt. All output from the container will immediately be displayed here, as long as we leave the window open. To stop this, simply press Ctrl+C to get back to the prompt. All output will be available in the log anyway, so no worries that you lose any information.
As you can see, the container got a generated hostname 4115d4529433, which is not really useful. In fact, this is the id of the running container.
Just try out the Web Client url in the browser, and you will see that it actually connects to the Web Client inside the container. You will get a warning about the certificate though. To get the certificate, look for the correct URL under files and download the certificate from there. Follow the instructions from Waldo’s blog to import it in the Trusted Root Certification Authorities certificate store on the host VM!
Why on the host VM? Because at this moment, you cannot connect to this container from the outside world, it is only available from inside the VM.
How to connect to the container with VS Code
Inside the VM you will find Visual Studio code. With the output from the docker run command above, you will be able to create a workspace in Visual Studio.
In the launch.json change these settings to the values in the output from docker:
- server = <Dev. server>
- serverInstance = <Dev. serverInstance>
- authentication = UserPassword
Remember to change the app.json to the correct language setting. If you have the US image, then you don’t have to change.
Now you can download the symbols. This will prompt you for the username and password. Use the username and password from the docker output window. Now you have used these settings from the docker output in your VS Code project and the symbols will be downloaded.
Remember to set the tenant to “” in launch.json after you downloaded the symbols. Otherwise the Web Client will not start. This is a known issue and will be solved in a future update.
With this information, you should be able to start using the docker images. There is of course a lot more to know about docker. The topics in this post is just scratching the surface. See https://docs.docker.com/engine/reference/commandline/docker/ for a complete reference of the command line options.
I have one scenario left out: making the docker container accessible from outside. That is perfectly possible. I will come back to that in another blog post.
Pingback: Docker Tips for NAV Development Preview September Update - Kauffmann @ Dynamics NAV - Dynamics NAV Users - DUG
If you want to simplify your life and make the formatting ‘usable’ you can create your templates. The templates are “per-user” and you can find them here:
$env:USERPROFILE\.docker\config.json
In your case you can add the following element and make it persistent:
“psFormat”: “table {{.ID}}\t{{.Image}}\t{{.Status}}\t{{.Names}}”
Or in the case of “docker stats” command you can use the following (this one is really much better than the standard one because in the original you don`t see container names):
“statsFormat”: “table {{.Name}}\t{{.CPUPerc}}\t{{.MemUsage}}\t{{.MemPerc}}\t{{.NetIO}}\t{{.BlockIO}}\t{{.PIDs}}”,
Hi Kauffmann,
Your post is amazing, and I must admit, it’s an big help in a disarray situation. Where I have seen, NAV developers giving up on trying docker with NAV.
Can you please provide some detail information on how to import developer license in NAV docker container.
I referred your another post”http://www.kauffmann.nl/2017/09/12/how-to-get-access-to-code-in-nav-developer-preview-september-update/”, but not able to execute Import-NAVServerLicense -ServerInstance NAV -LicenseFile ‘C:\run\my\mylicense.flf’.
I get following error
Import-NAVServerLicense : Cannot bind parameter ‘LicenseFile’ to the target. Exception setting “LicenseFile”: “Could
not find a part of the path ‘C:\run\my\888.flf’
The folder “myfolder” is already there in my machine root and the license file 888.flf is also present.
Regards,
I assume the command you use is
Import-NAVServerLicense -ServerInstance NAV -LicenseFile C:\run\my\888.flf
Is that correct? In this case you even could do it without quotes around the path because there is no space in it.
The command looks ok to me. You could verify if c:\run\my contains the file by running the command dir c:\run\my inside the PowerShell window. If that lists all files that are in c:\myfolder of the host, then that proves that the container has access to the file. If not, then something is wrong with container. In that case, try to create a new VM to be sure you get the latest fixes.
If the files are visibile, then it must be your command, something like incorrect quotes or so. Cannot say for sure, it looks ok to me.
Hi,
Thanks for replying. I forgot to mention that the container is pulled in local machine and not through Azure VM.
Below command was used to create the container in the fresh installation machine.
docker run -m 3G -it -e ACCEPT_EULA=Y -e ClickOnce=Y navdocker.azurecr.io/dynamics-nav:devpreview-finus
Because the myfolder not created in the local machine. We are bit stuck and identifying how to map a folder in a running container.
Ah, that’s the problem! The docker run command must include an option which local folder must be shared with the container.
Remove the docker container and run a new one with this command:
docker run -m 3G -it -e ACCEPT_EULA=Y -e ClickOnce=Y -v c:\myfolder:c:\run\my navdocker.azurecr.io/dynamics-nav:devpreview-finus
The added option is: -v c:\myfolder:c:\run\my
Hi,
Thanks a lot your suggestion worked and the container got started.
While trying to install the NAV Development environment through the ClickOnce link, nothing happens.
Tried installing development environment by running the internet explorer and Chrome as Administrator but same problem.
Also can you please guide us, in how to save the container, so next time when the server gets restarted we get the same container and settings.
As per our last experience, when the server get restart the container doesn’t start and need to run everything again to make the container up.
Very difficulty for testing some thing, since one day we make entries for testing and 2nd day the container is not running/usable.
First of all: I’m certainly not the expert on Docker.
Some remarks:
How did you get the image locally in the first place? It is currently behind a password if I’m correct.
The docker container is currently only shipped on Azure VM. The latest Azure image (as of this week) supports restarting the container when the host reboots. I strongly suggest that you use this Azure VM.
I have tried to run containers on Windows 10, but that didn’t really workout well. Probably due to my limited knowledge. Anyway, from what I’ve experienced I learned to go with Windows Server 2016, either on HyperV or Azure.
Please, send in questions at GitHub, people there know more. https://github.com/Microsoft/AL/issues/
Hi,
Thanks for sharing the details, yes the image is behind the firewall. We are an ISV partner and working on on-Premises NAV and D365 and have obtain the credentials from Mr. Freddy.
I posted the comments on Yammer group too. on Windows Server 2016 it works without any issue. But for on premises Windows 10 Anniversary update laptop does not behave accordingly.