Capturing Logs in Docker Desktop

Docker Desktop runs a Virtual Machine to host Docker containers. Each component within the VM (including the Docker engine itself) runs as a separate isolated container. This extra layer of isolation introduces an interesting new problem: how do we capture all the logs so we can include them in Docker Desktop diagnostic reports? If we do nothing then the logs will be written separately into each individual container which obviously isn’t very useful!

The Docker Desktop VM boots from an ISO which is built using LinuxKit from a list of Docker images together with a list of capabilities and bind mounts. For a minimal example of a LinuxKit VM definition, see https://github.com/linuxkit/linuxkit/blob/master/examples/minimal.yml — more examples and documentation are available in the LinuxKit repository. The LinuxKit VM in Docker Desktop boots in two phases: in the first phase, the init process executes a series of one-shot “on-boot” actions sequentially using runc to isolate them in containers. These actions typically format disks, enable swap, configure sysctl settings and network interfaces. The second phase contains “services” which are started concurrently and run forever as containerd tasks.

The following diagram shows a simplified high-level view of the boot process:

By default the “on-boot” actions’ stdout and stderr are written both to the VM console and files in /var/log/onboot.* while the “services” stdout and stderr are connected directly to open files in /var/log which are left to grow forever.

Initially we considered adding logging to the VM by running a syslog compatible logging daemon as a regular service that exposes /dev/log or a port (or both). Other services would then connect to syslog to write logs. Unfortunately a logging daemon running in a service would start later — and therefore miss all the logs from — the “on-boot” actions. Furthermore, since services start concurrently, there would be a race between the syslog daemon starting and syslog clients starting: either logs would be lost or each client startup would have to block waiting for the syslog service to start. Running a syslog daemon as an “on-boot” action would avoid the race with services, but we would have to choose where to put it in the “on-boot” actions list. Ideally we would start the logging daemon at the beginning so that no logs are lost, but then we would not have access to persistent disks or the network to store the logs anywhere useful.

In summary we wanted to add a logging mechanism to Docker Desktop that:

was able to capture all the logs — both the on-boot actions and the service logs;could write the logs to separate files to make them easier to read in a diagnostics report;could rotate the log files so they don’t grow forever;could be developed within the upstream LinuxKit project; andwould not force existing LinuxKit users to rewrite their YAML definitions or modify their existing code.

We decided to implement first-class support for logging by adding a “memory log daemon” called memlogd which starts before the first on-boot action and buffers in memory the last few thousand lines of console output from each container. Since it is only buffering in memory, memlogd does not require any network or persistent storage. A log downloader starts later, after the network and persistent storage is available, connects to memlogd and streams the logs somewhere permanent.

As long as the logs are streamed before the in-memory buffer is full, no lines will be lost. The use of memlogd is entirely optional in LinuxKit; if it is not included in the image then logs are written to the console and directly to open files as before.

Design

We decided to use the Go library container/ring to create a bounded circular buffer. The buffer is bounded to prevent a spammy logging client consuming too much memory in the VM. However if the buffer does fill, then the oldest log lines will be dropped. The following diagram shows the initial design:

Logging clients send log entries via a file descriptor (labelled “linuxkit-external-logging.sock”). Log downloading programs connect to a query socket (labelled “memlogdq.sock”), read logs from the internal buffer and write them somewhere else.

Recall that one of our design goals was to avoid making changes to each individual container definition to use the new logging system. We don’t want to explicitly bind-mount a logging socket into the container or have to modify the container’s code to connect to it. How then do we capture the output from containers automatically and pass it all to the linuxkit-external-logging.sock?

When an on-boot action or service is launched, the VM’s init system creates a FIFO (for containerd) or a socketpair (for runc) for the stdout and stderr. By convention LinuxKit containers normally write their log entries to stderr. Therefore if we modify the init system, we can capture the logs written to the stderr FIFOs and the socketpairs without having to change the container definition or the code. Once the logs have been captured, the next step is to send them to  memlogd — how do we do that?

A little known feature of Linux is that you can pass open file descriptors to other processes via Unix domain sockets. We can, instead of proxying log lines, just pass an open socket directly to memlogd. We modified the design for memlogd to take advantage of this:

When the container is started, the init system passes the stdout and stderr file descriptors to memlogd along with the name of the container. Memlogd monitors all its file descriptors in a select-loop. When data is available it will be read, tagged with the container name and timestamped before it is appended to the in-memory ringbuffer. When the container terminates, the fd is closed and memlogd removes the fd from the loop.

So this means:

we don’t have to modify container YAML definitions or code to be aware of the logging system; andwe don’t have to proxy logs between the container and memlogd.

Querying memlogd

To see memlogd in action on a Docker Desktop system, try the following command:

docker run -it –privileged –pid=host justincormack/nsenter1 /usr/bin/logread -F -socket /run/guest-services/memlogdq.sock

This will run a privileged container in the root namespace (containing the “memlogdq.sock” used for querying the logs) and run the utility “logread”, telling it to “follow” the stream i.e. to keep copying from memlogd to the terminal until interrupted. The output looks like this:

2019-02-22T16:04:23Z,docker;time=”2019-02-22T16:04:23Z” level=debug msg=”registering ttrpc server”

Where the initial timestamp indicates when memlogd received the message and “docker” shows that the log came from the docker service. The rest of the line is the output written to stderr.

Kernel logs (kmsg)

In Docker Desktop we include the Linux kernel logs in diagnostic reports to help us understand and fix Linux kernel bugs. We created the kmsg-package for this purpose. When this service is started, it will connect to /dev/kmsg, stream the kernel logs and output them to stderr. As the stderr is automatically sent to memlogd, the kernel logs will then also be included in the VM’s logs and will be included in the diagnostic report. Note that reading kernel logs via /dev/kmsg is a privileged operation and so the kmsg service needs the capability CAP_SYSLOG.

Persisting the logs

In Docker Desktop we persist the log entries to files (one per service), rotate them when they become large and then delete the oldest to avoid leaking space. We created the  logwrite package for this purpose. When this service is started, it connects to the query socket memlogdq.sock, downloads the logs as they are written and manages the log files.

Summary

We now have a relatively simple and lightweight, yet extendable logging system that provides the features we need in Docker Desktop: it captures logs from both “on-boot” actions and services, and persists logs to files with rotation after the file system has been mounted. We developed the logging system in the upstream LinuxKit project where we hope the simple and modular design will allow it to be easily extended by other LinuxKit developers.

References

Documentation for memlogd in the LinuxKit repoAn example use of memlogdThe source code for memlogdThe kmsg service which allows kernel log messages to be included
The post Capturing Logs in Docker Desktop appeared first on Docker Blog.
Quelle: https://blog.docker.com/feed/

5 Software Development Predictions for 2020

Photo by Jamie Street on Unsplash

To kick off the new year, we sat down with Docker CEO Scott Johnston and asked him what the future holds for software development. Here are his 2020 predictions and trends to keep an eye on.
Existing Code and Apps Become New Again
Developers will find new ways to reuse existing code instead of reinventing the wheel to start from scratch. Additionally, we’ll see companies extend the value to existing apps by adding more functionality via microservices.
The Changing Definition of a Modern Application
Today’s applications are more complex than those of yesterday. In 2020, modern apps will power tomorrow’s innovation and this requires a diverse set of tools, languages and frameworks for developers. Developers need even more flexibility to address this new wave of modern apps and evolve with the rest of the industry.
Containers Pave the Way to New Application Trends
Now that containers are typically considered a common deployment mechanism, the conversation will evolve from the packaging of individual containers to the packaging of the entire application (which are becoming increasingly diverse and distributed). Organizations will increasingly look for guidance and solutions that help them unify how they build and manage their entire application portfolio no matter the environment: on premises, hybrid/multi-cloud, edge, etc.
Digital Transformation Transforms Itself 
Digital transformation was the buzzword of 2019, but we’ll see the term become less ambiguous this year. It’ll evolve to have a more specific meaning: a process for creating business impact through modernizing existing technology investments and delivering new applications/services.
A Container-First Strategy Proves Itself 
Developers have long been proponents of containers, but there’s been a huge shift toward establishing container-first strategies that are foundational to business transformation. 2020 will mark the year that these container-centric initiatives become the go-to-approach and play out on a larger scale. This will happen across enterprises and industries as it proves immediate impact by providing a clear path to the cloud for all applications, regardless of programming language or whether they’re three-tier brownfield apps or cloud-native greenfield microservices, while reducing cost and risk.
The post 5 Software Development Predictions for 2020 appeared first on Docker Blog.
Quelle: https://blog.docker.com/feed/

2019 Docker Community Awards

The Docker Community is the heart of Docker’s success and a huge reason why Docker was named the most wanted and second most loved developer tool in the 2019 Stack Overflow Survey. This year, we honored the following members of the Docker Community for their exemplary contributions to Docker users around the globe. On behalf of Docker and developers everywhere, thank you for your passion and commitment to this community!

Ajeet Singh Raina, Bangalore, India
Ajeet is a Docker Captain and Docker Community Leader for Docker Bangalore, the largest Docker Meetup in the world with nearly 8,000 members. His meetups are more like mini-conferences, commonly exceeding hundreds of RSVPs and involving free hands on workshop and training content that he and his docker community have developed. Ajeet is also a prolific blogger, sharing docker and kubernetes content on his blog Collabnix, which had over a million views in 2019. Ajeet also helped to organize and/or speak at more than 30+ events over the past year. This year, Ajeet was recognized by his fellow Captains to receive the Tip of the Captains Hat Award for his tireless dedication to sharing his expertise with the broader tech community. Keep up with Ajeet by following him on twitter, github, or his blog.

Dave Henderson, Ottawa, Canada

Dave has organized Docker Ottawa meetups since 2016 and is a frequent speaker to his local community. “My involvement in the Docker community over these past few years has been a particular highlight for me. It’s rewarding to see how enthusiastic the members of the Ottawa community are to be connecting and developing their skills, especially when those new to Docker begin to understand and master key concepts. Thank you to the Ottawa Docker community, my fellow community leaders, and especially Docker for a great 2019; I’m excited to see what 2020 will bring!”

Dominique Top, London
Dominique Top, or Dom to those that know her, has been the Docker London Community Leader for nearly 2 years. She knows how to keep meetups fun and is full of innovative ideas to support her local tech community. Last year she helped to create Meetup Mates to ensure that those who wanted to attend a meetup didn’t have to do it alone.

Gloria Gonzalez Palma, Mexico City
Gloria organized a record 12 meetups in 2019, including the Docker Birthday, Fall #LearnDocker workshop, and a Docker Posada, a traditional Mexican party held in December, complete with a pinata. “Being a community leader means to me, part of my life, I have grown with the community and the community has grown with me. It is a relation win, win, I love it.”

Imre Nagi, Jakarta, Indonesia
Imre started sharing Docker with others as a student at Carnegie Mellon University and then formed the only Docker meetup in Indonesia once he returned home. “I decided to come back home after my master grad in the US simply because I want to be part of an exciting journey in the Indonesia tech scene. Being in the Docker community gives me the opportunity to do that and to reach more people and cities in Indonesia and to do something greater and greater every day for the community :)” Imre organized two #LearnDocker workshops this fall to be able to support a wider swath of his country’s demand for the content.

Taygan Pillay, Cape Town, South Africa
Taygan organizes the Docker community in Cape Town, South Africa, sharing containers across the tech scene there. “Being a Docker CL has been a rewarding experience by being part of the container movement, at the same time helping build the community. Meeting people from diverse industries striving for a common goal of streamlined deployments and development life cycles allows insights very few other opportunities provide.”

Connect with the Docker community by attending a local meetup, joining the virtual Docker meetup group, and chatting with other users on the Docker Community Slack Channel.

The post 2019 Docker Community Awards appeared first on Docker Blog.
Quelle: https://blog.docker.com/feed/

Year in Review: The Most Loved Docker Articles, Blogs and Tweets of 2019

Photo by NordWood Themes on Unsplash
As this decade comes to a close, we are rounding up some of your favorite content from 2019. Catch up on anything you missed and get ready for a lot more to come in 2020!
Docker Captain Content
Brian Christner did an analysis of VMware, Docker, and Kubernetes Google Trends and the results just might surprise you. . . or maybe not.
John Lees Miller updated his 2016 Lessons from Building a Node App in Docker. Run through the updated tutorial to learn how to Dockerize your node.js apps by setting up the socket.io chat example with Docker, from scratch to production-ready. 
Ajeet Singh Raina wrote nearly 30 blogs in 2019, and the most popular was 5 Minutes to Kubernetes Dashboard running on Docker Desktop for Windows 2.0.0.3. Find yourself five minutes before the end of the year to try this out yourself.
Łukasz Lach and Thomas Shaw spread holiday cheer with some seasonal docker run commands:

$ docker run -it lukaszlach/merry-christmas

docker run –rm -t tomwillfixit/hohoho

Bret Fisher hosts a weekly Docker and DevOps YouTube live show – a fun and educational way to spend an hour on Thursdays. Check out his top episodes of 2019 here.
Top Blog Posts from Docker’s Blog

Hands down the most popular blog of 2019 was Docker Engineer Tibor’s Vass’ Guide to Dockerfile Best Practices. And if video is more your style, check out his and Sebastiaan Van Stijin’s DockerCon talk on the same topic.
Docker developers love to tinker, so it was no surprise that Paulo Frazao’s Happy Pi Day tutorial, walking developers through how to install Docker Engine – Community (CE) 18.09 on Raspberry Pi made the top five this year. Learn more about how to build multi-arch apps with Elton Stoneman’s Online Meetup: Building Multi-Arch Apps with BuildX.
 Updates to Docker Hub were also really popular reads in 2019, including Shanea Leven’s Two-Factor Authentication and Personal Access Tokens posts.
Lastly, Docker Desktop Product Manager Ben De St Paer-Gotch unveiled the availability of Docker’s Technical Preview of Docker Desktop for WSL 2 and shares five things to try out. 
Top Tweets
Holidays, cheat sheets, developer love and how to’s were a hit on Twitter this year:

Articles
Docker CEO Scott Johnston outlines his predictions on What 2020 Holds for Developers.
StackOverflow released its 2019 Developer Survey, and Docker ranked as the #1 most wanted, #2 most loved and #3 most used platform.
A glimpse into what Docker will be up to next year as Docker CEO Scott Johnston Foresees Developer Tool Advances in 2020 and Beyond.
Docker is listed first in this overview of the Best Open Source Innovations of the Decade! 
Thanks for being a part of the Docker Community! We look forward to more great content in the year ahead.
The post Year in Review: The Most Loved Docker Articles, Blogs and Tweets of 2019 appeared first on Docker Blog.
Quelle: https://blog.docker.com/feed/

Containers Today Recap: The Future of the Developer Journey

There was amazing attendance at Containers Today in Stockholm a couple of weeks ago. For those who were unable to make it, here is a quick overview of what I talked about at the event in my session around the future of the developer journey. 
Before we talk about what we think will change the journey, we need to think about why it changes. The fundamental goal of any change to the way of working for developers should be to reduce the number of boring, mundane and repetitive tasks that developers have to do or to allow them to reach new customers/solve new problems. Developers create amazing value for companies and provide solutions to customers’ real world problems. But if they are having to spend half of their time working out how to get things into the hands of their customers, then you are getting half the value.

Developer Evolution
The role of developers has changed a lot over the last ~40 years. Developers no longer deploy to mainframes or in house hardware, they don’t do waterfall deployments and not many of them write in machine code. Developers have to now think about web languages and ML, work in Extreme Agile DevOps teams (ok I made that up a bit) and deploy to the Cloud or to Edge devices. This change keeps happening as the entire industry tries to find new ways for developers to deliver value, deliver that value faster and reduce the number of mundane tasks for developers.
Today the process for getting value to customers is often described as the ‘outer loop’ of development, while the creative process of development, i.e. creating new features, is described as the ‘inner loop.’ 
In an ideal world, that outer loop is automated and uses modern CI/CD technologies to create a cycle of feedback that allows developers to create new features and fix bugs ever faster. This looks something like: 

Though this is an ideal world, this is not the case for a lot of developers. In the “The State of Developer Ecosystem 2019” report, only 45% of developers said that CI/CD was part of their regular tool set. This also means 55% of developers have yet to adopt it. This is one of the changes we think will start to accelerate in the near future. As CI/CD is democratized with new tools like Github Actions, we will see even small teams starting to adopt CI/CD over manual deployments.
Another big change in the outer loop is how people look at what they are passing through this outer loop. Developers are trying to get value out to customers but the concept of value is changing. As we moved away from monoliths, we have started to create individual services that are easier to work with and deploy. The idea of bundling these services with systems like Helm or CNAB tools is becoming more prominent as businesses consider that in isolation, a single container does not provide value to a customer. But a collection of these services together is the minimum set to deliver customer value. 
These may each be a separate microservice, but just a notifications service or a payment service won’t drive business value in isolation. 
For the outer loop, some of the big changes we see are changes to how things are deployed. 57% of developers are still not using orchestration (Slashdata Developer Report 16th Edition). The growth in orchestration and in particular K8s is going to change how we think about the hand off between developers and operations as we move towards more microservices in production than ever before. The complexity of this change will be compounded as production is likely to be on multiple clouds or on premises, and as over 50% of companies have a hybrid strategy and a multi cloud strategy.
For developers, all of these things are going to be impactful at a significant scale as we aim to develop the next 500 million apps by 2023 (IDC Analyse the Future). With Edge/IoT growing 10X between 2017-2025 (Allied Market Research), we are also going to need to think of new ways for developers to work with these technologies and extend their inner loop outside of their immediate machine. 
So in summary, we are going to see more bundled apps being deployed via CI/CD to orchestrators in the cloud and on prem, and movement between them. We will be building more of these apps than ever and they have to run anywhere, considering how they interface with the Edge and work as part of our inner loop for this on the Cloud. And finally, we strongly believe that the use of containers is going to be a driving factor and the underlying technology to enable this.
What’s Next for Developers
At Docker, we have started to look ahead at how we can build technology to help developers adopt some of these tools. 

For local developers, we have looked at how to accelerate people creating the next 500 million new applications with Application templates, enabling developers to create new containerized applications in seconds from existing examples. We have been working out how we can improve our IDE integration to make developers lives better where they work today. We have added a layer of GUI abstraction into Docker Desktop to make it simpler to understand all of these components.
We are also thinking about how we can extend the local development environment and the inner loop for new objects. We have Docker Context to allow developers to work on a remote instance within their inner loop and ARM builds in Docker desktop for Working with the Edge.
And to deploy value in the future, we have Docker App for bundling the value of more than one container service to get it running in production.
We are also thinking about things like CI, moving between platforms and generally how to make it easier for the next 10 million developers to get started with Docker. We know that a lot of these technologies have been embraced by early adopters. But as all of these new technologies and changes start to reach the early majority, we need to think about how we are going to scale all of said technologies and keep mundane tasks away from developers! 
Containers Today was a fantastic event with great turnout. Hopefully this post gives some insight into my talk at the event and the trends we see. If you have other thoughts on what the future of the developer journey holds, please reach out to us! 
The post Containers Today Recap: The Future of the Developer Journey appeared first on Docker Blog.
Quelle: https://blog.docker.com/feed/

Deep Dive Into the New Docker Desktop filesharing Implementation Using FUSE

The latest Edge release of Docker Desktop for Windows 2.1.7.0 has a completely new filesharing system using FUSE instead of Samba. The initial blog post we released presents the performance improvements of this new implementation and explains how to give feedback. Please try it out and let us know what you think. Now, we are going to go into details to give you more insight about the new architecture.
New Architecture
Instead of Samba running over a Hyper-V virtual network, the new system uses a Filesystem in Userspace (FUSE) server running over gRPC over Hypervisor sockets.
The following diagram shows the path taken by a single request from a container, for example to read a PHP file:

In step (1) the web-server in the container calls “read” which is a Linux system call handled by the kernel’s Virtual File System (VFS) layer. The VFS is modular and supports many different filesystem implementations. In our case we use Filesystem in Userspace (FUSE) which sends the request to a helper process running inside the VM labelled “FUSE client.” This process runs within the same namespace as the Docker engine. The FUSE client can handle some requests locally, but when it needs to access the host filesystem it connects to the host via “Hypervisor sockets.”
Hypervisor Sockets
Hypervisor sockets are a shared-memory communication mechanism which enables VMs to communicate with each other and with the host. Hypervisor sockets have a number of advantages over using regular virtual networking, including:

since the traffic does not flow over a virtual ethernet/IP network, it is not affected by firewall policies
since the traffic is not routed like IP, it cannot be mis-routed by VPN clients
since the traffic uses shared memory, it can never leave the machine so we don’t have to worry about third parties intercepting it

Docker Desktop already uses these sockets to forward the Docker API, to forward container ports, and now we use them for filesharing on Windows too!
Returning to the diagram, the FUSE client creates sockets using the AF_VSOCK address family, see step (3). The kernel contains a number of low-level transports, one per hypervisor. Since the underlying hypervisor is Hyper-V, we use the VMBus transport. In step (4) filesystem requests are written into the shared memory and read by the VMBus implementation in the Windows kernel. A FUSE server userspace process running in Windows reads the filesystem request over an AF_HYPERV socket in step (5).
FUSE Server
The request to open/close/read/write etc is received by the FUSE server, which is running as a regular Windows process. Finally in step (6) the FUSE server uses the Windows APIs to perform the read or write and then returns the result to the caller.
The FUSE server runs as the user who is running the Docker app, so it only has access to the user’s files and folders. There is no possibility of the VM gaining access to any other files, as could happen in the previous design if a local admin account is used to mount the drive in the VM.
Event Injection
When files are modified in Linux, the kernel generates inotify events. Interested applications can watch for these events and take action. For example, a React app run with
$ npm start
will watch for inotify events and automatically recompile when code changes and trigger the browser to refresh automatically, as shown in this video. In previous versions of Docker Desktop on Windows we weren’t able to generate inotify events so these styles of development simply wouldn’t work.
Injecting inotify events is quite tricky. Normally a Linux VFS implementation like FUSE wouldn’t generate the events itself; instead the common code in the higher layer generates events as a side-effect of performing actions. For example when the VFS “unlink” is called and returns successfully then the “unlink” event will be generated. So when the user calls “unlink” under Windows, how does Linux find out about it?
Docker Desktop watches for events on the host when the user runs docker run -v. When an “unlink” event is received on the host, a request to “please inject unlink” is forwarded over gRPC to the Linux VM. The following diagram shows the sequence of operations:

A thread with a well-known pid inside the FUSE client in Linux “replays” the request by calling “unlink,” even though the directory has actually already been removed. The FUSE client intercepts requests from this well-known pid and pretends that the unlink hasn’t happened yet. For example, when FUSE_GETATTR is called, the FUSE client will say, “yes the directory is still here” (instead of ENOENT). When the FUSE_UNLINK is called, the FUSE client will say, “yes that worked” (instead of ENOENT). As a result of the successful FUSE_UNLINK the Linux kernel generates the inotify event.
Caching
As you can see from the architecture diagram above, each I/O request has to make several user/kernel transitions and VM/host transitions to complete. This means the latency of a filesystem operation is much higher than the case when all the files are local in the VM. We have mitigated this with aggressive use of kernel caching, so many requests can be avoided altogether. We:

use the file attribute cache which minimises FUSE_GETATTR requests
set FOPEN_CACHE_DIR which caches directory contents in the kernel page cache
set FOPEN_KEEP_CACHE which caches file contents
we set CAP_MAX_PAGES to increase the maximum request size
We use a modern 4.19 series kernel with the latest FUSE patches backported

Since we have enabled so many caches we have to carefully handle cache invalidation. When a user runs docker run -v and we are monitoring the filesystem events for inotify event injection, we also use these events to invalidate cache entries. When the docker run -v exits and the watches are disabled we invalidate all the cache entries.
Future Evolution
We have lots of ideas to improve the performance further by even more aggressive use of caching. For example, in the Symfony benchmark above, the majority of the remaining FUSE calls in the cached case are calls to open and close file handles; even though the file contents is itself cached (and hasn’t changed). We may be able to make these open and close calls lazy and only call them when needed.
The new filesystem implementation is not relevant on WSL 2 (currently available on early Windows Insider builds), since that already has a native filesharing mode which uses 9P. Of course we will keep benchmarking, optimising and incorporating user feedback to always use the best available filesharing implementation across all OS versions.
The post Deep Dive Into the New Docker Desktop filesharing Implementation Using FUSE appeared first on Docker Blog.
Quelle: https://blog.docker.com/feed/

New Filesharing Implementation in Docker Desktop Windows Improves Developer Inner Loop UX

Photo by Helloquence on Unsplash

A common developer workflow when using frameworks like Symfony or React is to edit the source code using a Windows IDE while running the app itself in a Docker container. The source is shared between the host and the container with a command like the following:
$ docker run -v C:Usersme:/code -p 8080:8080 my-symfony-app
This allows the developer to edit the source code, save the changes and immediately see the results in their browser. This is where file sharing performance becomes critical.
The latest Edge release of Docker Desktop for Windows 2.1.7.0 has a completely new filesharing implementation using Filesystem in Userspace (FUSE) instead of Samba which:

uses caching to (for example) reduce page load time in Symfony by up to 60%;
supports Linux inotify events, triggering automatic recompilation / reload when the source code is changed;
is independent of how you authenticate to Windows: smartcard, Azure AD are all fine;
always works irrespective of whether your VPN is connected or disconnected;
reduces the amount of code running as Administrator.

Your feedback needed!
This improvement is available today in the Edge 2.1.7.0 release and will roll-out to the stable channel later once we’ve had enough positive feedback. Please download it, give it a try and let us know how it goes.  If you discover any problems, please report them on GitHub and make sure you fill descriptions and reproduction steps so that we can quickly investigate.
DOWNLOAD

Big performance improvements
Performance is vital when application source code is being shared between the host and a container. For example when a developer uses the Symfony PHP framework, edits the source code and then reloads the page in the browser, the web-server in the container must re-read many PHP files stored on the host. This must be fast.
The following graph shows the time taken to load a page of a simple symfony demo in three configurations:

Previous version: this is the implementation in earlier versions of Docker Desktop
Docker Desktop Edge 2.1.7.0: this is the new (faster!) implementation
In-container: the files are not shared from the host at all, instead they are stored in the container to show the upper limit on possible future performance.

The two bars on the left hand side show the latency (in seconds) using an older version of Docker Desktop. Note that the second fetch is only slightly better than the first, suggesting that the effect of caching is small.
The two bars on the right hand side show the latency when the files are not shared at all, but are stored entirely inside the VM. This is the upper limit on performance if the volume sharing system were perfect and had zero overheads.
The two bars in the middle show the latency when the files are shared with the new system in Docker Desktop Edge 2.1.7.0. The initial (uncached) fetch is already better than with the previous Desktop version, but the second (cached) fetch is 60% faster!
Additional enhancements
As well as big performance improvements, the new implementation has the following additional benefits:

The new version can’t conflict with organisation-wide security policies as we don’t need to use Administrator privileges to share the drive and create a firewall exception for port 445.
The new version doesn’t require the user to enter their domain credentials. Not only is this fundamentally more secure, but it avoids the user having to re-enter their credentials every time they change their password. Many organisations require regular password changes, which means the user needed to refresh the credentials frequently.
The new version supports users who authenticate via a smartcard, or AzureAD or any other method. Previously we could only support users who login with a username and password.
The new version is immune to a class of problems caused by enterprise VPN clients and endpoint security software clashing with the Hyper-V network adapter.

Stay tuned for a follow up post that deep dives into the new Docker Desktop filesharing implementation using FUSE.
The post New Filesharing Implementation in Docker Desktop Windows Improves Developer Inner Loop UX appeared first on Docker Blog.
Quelle: https://blog.docker.com/feed/

Managing the TICK Stack with Docker App

Photo by Sergio Souza on Unsplash
Docker Application eases the packaging and the distribution of a Docker Compose application. The TICK stack – Telegraf, InfluxDB, Chronograf, and Kapacitor – is a good candidate to illustrate how this actually works. In this blog, I’ll show you how to deploy the TICK stack as a Docker App.
About the TICK Stack
This application stack is mainly used to handle time-series data. That makes it a great choice for IoT projects, where devices send data (temperature, weather indicators, water level, etc.) on a regular basis.
Its name comes from its components:
– Telegraf
– InfluxDB
– Chronograf
– Kapacitor
The schema below illustrates the overall architecture, and outlines the role of each component.

Data are sent to Telegraph and stored in an InfluxDB database. Chronograf can query the database through a web interface. Kapacitor can process, monitor, and raise alerts based on the data.
Defining the Application in a Compose File
The tick.yml file below defines the four components of the stack and the way they communicate with each other:
version: ‘3.7’
services:
  telegraf:
    image: telegraf
    configs:
    – source: telegraf-conf
      target: /etc/telegraf/telegraf.conf
    ports:
    – 8186:8186
  influxdb:
    image: influxdb
  chronograf:
    image: chronograf
    ports:
    – 8888:8888
    command: [“chronograf”, “–influxdb-url=http://influxdb:8086″]
  kapacitor:
    image: kapacitor
    environment:
    – KAPACITOR_INFLUXDB_0_URLS_0=http://influxdb:8086
configs:
  telegraf-conf:
    file: ./telegraf.conf
Telegraf’s configuration is provided through a Docker Config object, created out of the following telegraf.conf file:
[agent]
  interval = “5s”
  round_interval = true
  metric_batch_size = 1000
  metric_buffer_limit = 10000
  collection_jitter = “0s”
  flush_interval = “5s”
  flush_jitter = “0s”
  precision = “”
  debug = false
  quiet = false
  logfile = “”
  hostname = “$HOSTNAME”
  omit_hostname = false
[[outputs.influxdb]]
  urls = [“http://influxdb:8086″]
  database = “test”
  username = “”
  password = “”
  retention_policy = “”
  write_consistency = “any”
  timeout = “5s”
[[inputs.http_listener]]
  service_address = “:8186″
[cpu]
  # Whether to report per-cpu stats or not
  percpu = true
  # Whether to report total system cpu stats or not
  totalcpu = true
This configuration:

Defines an agent that gathers host CPU metrics on a regular basis.
Defines an additional input method allowing Telegraf to receive data over HTTP.
Specifies the name of the database the data collected/received will be stored.

Deploying the application from Docker Desktop
Now we will deploy the application using Swarm first, and then using Kubernetes to illustrate some of the differences.
Using Swarm to Deploy the TICK Stack
First we setup a local Swarm using the following command:
$ docker swarm init
Then we deploy the TICK stack as a Docker Stack:
$ docker stack deploy tick -c tick.yaml
Creating network tick_default
Creating config tick_telegraf-conf
Creating service tick_telegraf
Creating service tick_influxdb
Creating service tick_chronograf
Creating service tick_kapacitor
This creates:

A network for communication between the application containers 
A Config object containing the Telegraf configuration we defined in telegraf.conf
The 4 services composing the TICK stack

It only takes a couple of seconds before the application is up and running. Now we can verify the status of each service.
$ docker service ls
ID                  NAME MODE                REPLICAS IMAGE PORTS
74zkf54ruztg        tick_chronograf replicated          1/1 chronograf:latest *:8888->8888/tcp
y97hcx3yyjx6        tick_influxdb replicated          1/1 influxdb:latest
fm4uckqlvhvt        tick_kapacitor replicated          1/1 kapacitor:latest
12zl0sa678xh        tick_telegraf replicated          1/1 telegraf:latest *:8186->8186/tcp
Only Telegraf and Chronograf are exposed to the outside world:

Telegraf is used to ingest data through port 8186
Chronograf is used to visualize the data and is available through a web interface on local port 8888

To query data from the Chronograf interface, we first need to send some data to Telegraf.
Sending Test data
First we will use the lucj/genx Docker image to generate data following a cosine distribution (a couple of other simple distributions are available).
$ docker run lucj/genx
Usage of /genx:
 -duration string
      duration of the generation (default “1d”)
 -first float
      first value for linear type
 -last float
      last value for linear type (default 1)
 -max float
       max value for cos type (default 25)
 -min float
       min value for cos type (default 10)
 -period string
       period for cos type (default “1d”)
 -step string
       step / sampling period (default “1h”)
 -type string
       type of curve (default “cos”)
We will generate three days of data, with a one day period, min/max values of 10/25 and a sampling step of one hour; that will be enough for our tests.
$ docker run lucj/genx:0.1 -type cos -duration 3d -min 10 -max 25 -step 1h > /tmp/data
We then send the data to the Telegraf HTTP endpoint with the following commands:
PORT=8186
endpoint=”http://localhost:$PORT/write”
cat /tmp/data | while read line; do
  ts=”$(echo $line | cut -d’ ‘ -f1)000000000″
  value=$(echo $line | cut -d’ ‘ -f2)
  curl -i -XPOST $endpoint –data-binary “temp value=${value} ${ts}”
done
Next, from the Explore tab in the Chronograf web interface we can visualize the data using the following query:
select “value” from “test”.”autogen”.”temp”
We will see a neat cosine distribution:

With just a couple of commands, we have deployed the TICK stack on a Swarm cluster, sent time series data and visualized it.
Finally, we remove the stack:
$ docker stack rm tick
Removing service tick_chronograf
Removing service tick_influxdb
Removing service tick_kapacitor
Removing service tick_telegraf
Removing config tick_telegraf-conf
Removing network tick_default
We have shown how to deploy the application stack with Docker Swarm. Now we will deploy it with Kubernetes.
Using Kubernetes to Deploy the TICK Stack
From Docker Desktop, deploying the same application on a Kubernetes cluster is also a simple process.
Activate Kubernetes from Docker Desktop
First, activate Kubernetes from the Docker Desktop settings:

A local Kubernetes cluster starts quickly and is accessible right from our local environment.

When the Kubernetes cluster is created, a configuration file (also known as kubeconfig) is created locally (usually in ~/.kube/config), or used to enrich this file if it already exists. This configuration file contains all the information needed to communicate with the API Server securely:

The cluster’s CA
The API Server endpoint
The default user’s certificate and private key

Creating a new Docker context
Docker 19.03 introduced the context object. It allows you to quickly switch the CLI configuration to connect with different clusters. A single context exists by default as shown below:
$ docker context list
NAME                DESCRIPTION                       DOCKER ENDPOINT KUBERNETES ENDPOINT                           ORCHESTRATOR
default *           Current DOCKER_HOST based configuration   unix:///var/run/docker.sock https://kubernetes.docker.internal:6443 (default)   swarm
Note: as we can see from the ORCHESTRATOR column, this context can only be used to deploy workload on the local Swarm.
We will now create a new Docker context dedicated to run Kubernetes workloads. This can be done with the following command:
$ docker context create k8s-demo
  –default-stack-orchestrator=kubernetes
  –kubernetes config-file=$HOME/.kube/config
  –description “Local k8s from Docker Desktop”
  –docker host=unix:///var/run/docker.sock
Next, we verify that both contexts are now available:
$ docker context list
NAME                DESCRIPTION                       DOCKER ENDPOINT KUBERNETES ENDPOINT                           ORCHESTRATOR
default *           Current DOCKER_HOST based configuration   unix:///var/run/docker.sock https://kubernetes.docker.internal:6443 (default)   swarm
k8s-demo            Local k8s from Docker Desktop             unix:///var/run/docker.sock https://kubernetes.docker.internal:6443 (default)   kubernetes
Note: we could use a single context where both orchestrators are defined. In that case, the deployment would be done on Swarm and Kubernetes at the same time.
Next, we switch on the k8s-demo context:
$ docker context use k8s-demo
k8s-demo
Current context is now “k8s-demo”
Then we deploy the application in the same way we did before, but this time it will run on Kubernetes instead of Swarm.
$ docker stack deploy tick -c tick.yaml
Waiting for the stack to be stable and running…
chronograf: Ready [pod status: 1/1 ready, 0/1 pending, 0/1 failed]
influxdb: Ready [pod status: 1/1 ready, 0/1 pending, 0/1 failed]
kapacitor: Ready [pod status: 1/1 ready, 0/1 pending, 0/1 failed]
telegraf: Ready [pod status: 1/1 ready, 0/1 pending, 0/1 failed]

Stack tick is stable and running
Using the usual kubectl binary, we can verify all the Kubernetes resources have been created:
$ kubectl get deploy,po,svc
NAME                               READY UP-TO-DATE AVAILABLE AGE
deployment.extensions/chronograf   1/1 1 1 2m50s
deployment.extensions/influxdb     1/1 1 1 2m50s
deployment.extensions/kapacitor    1/1 1 1 2m49s
deployment.extensions/telegraf     1/1 1 1 2m49s

NAME                             READY STATUS RESTARTS AGE
pod/chronograf-c55797884-mp8gc   1/1 Running 0 2m50s
pod/influxdb-67c574845d-z6846    1/1 Running 0 2m50s
pod/kapacitor-57f6787666-t8j6l   1/1 Running 0 2m49s
pod/telegraf-6b8648884c-lq9t5    1/1 Running 0 2m49s

NAME                           TYPE CLUSTER-IP EXTERNAL-IP   PORT(S) AGE
service/chronograf             ClusterIP None <none>        55555/TCP 2m49s
service/chronograf-published   LoadBalancer 10.105.63.34 <pending>     8888:32163/TCP 2m49s
service/influxdb               ClusterIP None <none>        55555/TCP 2m49s
service/kapacitor              ClusterIP None <none>        55555/TCP 2m49s
service/kubernetes             ClusterIP 10.96.0.1 <none>        443/TCP 30h
service/telegraf               ClusterIP None <none>        55555/TCP 2m49s
service/telegraf-published     LoadBalancer 10.107.223.80 <pending>     8186:32460/TCP 2m49s
We can generate some dummy data and visualize them using Chronograf following the same process we did above for Swarm (I only show the result here as the process is the same):

Finally we remove the stack:
$ docker stack rm tick
Removing stack: tick
Note: we used the same command to remove the stack from Kubernetes or Swarm, but notice the output is not the same as each orchestrator handles different  resources / objects.
Defining the TICK stack as a DockerApp
We followed simple steps to deploy the application using both Swarm and Kubernetes. Now we’ll define it as a Docker Application to make it more portable, and see how it eases the deployment process. 
Docker App is shipped with Docker 19.03+ and can be used once the experimental flag is enabled for the CLI. This can be done in several ways:

modifying the config.json file (usually in the $HOME/.docker folder)

{
“experimental”: “enabled”
}

setting the DOCKER_CLI_EXPERIMENTAL environment variable

export DOCKER_CLI_EXPERIMENTAL=enabled
Once this is done, we can check that Docker App is enabled:
$ docker app version
Version: v0.8.0
Git commit: 7eea32b7
Built: Tue Jun 11 20:53:26 2019
OS/Arch: darwin/amd64
Experimental: off
Renderers: none
Invocation Base Image: docker/cnab-app-base:v0.8.0
Note: version 0.8 is currently the last version
Note: the Docker App command is experimental, which means that the feature is subject to change before being ready for production. The user experience will be updated in the next release.
Available commands in Docker App
Several commands are available to manage the lifecycle of a Docker Application, as we can see below. We will illustrate some of them later in this article.
$ docker app

Usage: docker app COMMAND

A tool to build and manage Docker Applications.

Commands:
bundle Create a CNAB invocation image and `bundle.json` for the application
completion Generates completion scripts for the specified shell (bash or zsh)
init Initialize Docker Application definition
inspect Shows metadata, parameters and a summary of the Compose file for a given application
install Install an application
list List the installations and their last known installation result
merge Merge a directory format Docker Application definition into a single file
pull Pull an application package from a registry
push Push an application package to a registry
render Render the Compose file for an Application Package
split Split a single-file Docker Application definition into the directory format
status Get the installation status of an application
uninstall Uninstall an application
upgrade Upgrade an installed application
validate Checks the rendered application is syntactically correct
version Print version information

Run ‘docker app COMMAND –help’ for more information on a command.

Creating a Docker Application Package for the TICK stack
We start with the folder which contains the Docker Compose file describing the application (tick.yml) and the Telegraf configuration file (telegraf.conf):
$ tree .
.
├── telegraf.conf
└── tick.yml
Next we create the Docker Application, named tick:
$ docker app init tick –compose-file tick.yml –description “tick stack”
Created “tick.dockerapp”
This creates the folder tick.dockerapp, and three additional files:
$ tree .
.
├── telegraf.conf
├── tick.dockerapp
│ ├── docker-compose.yml
│ ├── metadata.yml
│ └── parameters.yml
└── tick.yml

1 directory, 5 files

– docker-compose.yml is the copy of the tick.yml file- metadata.yml defines metadata and additional parameters
$ cat tick.dockerapp/metadata.yml
# Version of the application
version: 0.1.0
# Name of the application
name: tick
# A short description of the application
description: tick stack
# List of application maintainers with name and email for each
maintainers:
– name: luc
email:

– parameters.yml defines the default parameters used for the application (more on this in a bit). This file is empty by default.
Note: when initializing the Docker App, it’s possible to use the -s flag. This creates a single file with the content of the three files above instead of a folder / files hierarchy.
As the application uses the telegraf.conf file, we need to copy it into tick.dockerapp folder.
Environment settings
As we mentioned above, the purpose of the parameters.yml file is to provide default values for the application. Those values will replace some placeholders we will define in the application’s compose file. 
To illustrate this, we will consider a dev and a prod environments and assume those two only differ when it comes to the port exposed by the application to the outside world:
– Telegraf listens on port 8000 in dev and 9000 in prod
– Chronograf listens on port 8001 in dev and 9001 in prod
Note: In a real world application, differences between dev and prod would not be limited to a port number. The current example is over-simplified to make it easier to grasp the main concepts.
First, we create a parameter file for each environment:
– parameters.yml defines some default ports for both Telegraf and Chronograf services
// parameters.yml
ports:
telegraf: 8186
chronograf: 8888

– dev.yml specifies values for the development environment
// dev.yml
ports:
telegraf: 8000
chronograf: 8001
– prod.yml specifies values for the production environment
// prod.yml
ports:
telegraf: 9000
chronograf: 9001

Next we modify the docker-compose.yml file to add some placeholders:
$ cat tick.dockerapp/docker-compose.yml
version: ‘3.7’
services:
telegraf:
image: telegraf
configs:
— source: telegraf-conf
target: /etc/telegraf/telegraf.conf
ports:
— ${ports.telegraf}:8186
influxdb:
image: influxdb
chronograf:
image: chronograf
ports:
— ${ports.chronograf}:8888
command: [”chronograf”, “–influxdb-url=http://influxdb:8086″]
kapacitor:
image: kapacitor
environment:
— KAPACITOR_INFLUXDB_0_URLS_0=http://influxdb:8086
configs:
telegraf-conf:
file: ./telegraf.conf

As we can see in the changes above, the way to access the port for Telegraf is to use the ports.telegraf notation. The same approach is used for the Chronograf port.
The Docker App’s render command generates the Docker Compose file, substituting the variables ${ports.XXX} with the content of the settings file specified. The default parameters.yml is used if none are specified. As we can see below, the Telegraf port is now 8186, and the Chronograf one is 8888.
$ docker app render tick.dockerapp/
version: “3.7”
services:
chronograf:
command:
– chronograf
– –influxdb-url=http://influxdb:8086
image: chronograf
ports:
– mode: ingress
target: 8888
published: 8888
protocol: tcp
influxdb:
image: influxdb
kapacitor:
environment:
KAPACITOR_INFLUXDB_0_URLS_0: http://influxdb:8086
image: kapacitor
telegraf:
configs:
– source: telegraf-conf
target: /etc/telegraf/telegraf.conf
image: telegraf
ports:
– mode: ingress
target: 8186
published: 8186
protocol: tcp
configs:
telegraf-conf:
file: telegraf.conf

If we specify a parameters file in the render command, the values within that file are used. As we can see in the following example which uses dev.yml during the rendering, Telegraf is published on port 8000 and Chronograf on port 8001 (values specified in dev.yml):
$ docker app render tick.dockerapp –parameters-file tick.dockerapp/dev.yml
version: “3.7”
services:
chronograf:
command:
– chronograf
– –influxdb-url=http://influxdb:8086
image: chronograf
ports:
– mode: ingress
target: 8888
published: 8001
protocol: tcp
influxdb:
image: influxdb
kapacitor:
environment:
KAPACITOR_INFLUXDB_0_URLS_0: http://influxdb:8086
image: kapacitor
telegraf:
configs:
– source: telegraf-conf
target: /etc/telegraf/telegraf.conf
image: telegraf
ports:
– mode: ingress
target: 8186
published: 8000
protocol: tcp
configs:
telegraf-conf:
file: telegraf.conf
Inspecting the application
The inspect command provides all the information related to the application:
– Its metadata
– The services involved
– The default parameter values- The files the application depends on (telegraf.conf in this example)
$ docker app inspect tick
tick 0.1.0

Maintained by: luc

tick stack

Services (4) Replicas Ports Image
———— ——– —– —–
chronograf 1 8888 chronograf
influxdb 1 influxdb
kapacitor 1 kapacitor
telegraf 1 8186 telegraf

Parameters (2) Value
————– —–
ports.chronograf 8888
ports.telegraf 8186

Attachments (3) Size
————— —-
dev.yml 43B
prod.yml 43B
telegraf.conf 657B

Deploying the Docker App on a Swarm Cluster
First, we go back to the default context which references a Swarm cluster.
$ docker context use default
Next, we deploy the application as a Docker App:
$ docker app install tick.dockerapp –name tick –parameters-file tick.dockerapp/prod.yml
Creating network tick_default
Creating config tick_telegraf-conf
Creating service tick_telegraf
Creating service tick_influxdb
Creating service tick_chronograf
Creating service tick_kapacitor
Application “tick” installed on context “default”

Then we list the deployed application to make sure the one created above is there:
$ docker app list
INSTALLATION APPLICATION LAST ACTION RESULT CREATED MODIFIED REFERENCE
tick tick (0.1.0) install success 4 minutes 3 minutes
Next we list the services running on the Swarm cluster. We can see the values from the prod.yml parameters file have been taken into account (as the exposed ports are 9000 and 9001 for Telegraf and Chronograf respectively).
$ docker service ls
ID NAME MODE REPLICAS IMAGE PORTS
75onunrvoxgt tick_chronograf replicated 1/1 chronograf:latest *:9001->8888/tcp
vj1ttws2mw1u tick_influxdb replicated 1/1 influxdb:latest
q4brz1i45cai tick_kapacitor replicated 1/1 kapacitor:latest
i6kvr37ycnn5 tick_telegraf replicated 1/1 telegraf:latest *:9000->8186/tcp

Pushing the application to Docker Hub
A Docker application can be distributed through the Docker Hub via a simple push:
$ docker app push tick –tag lucj/tick:0.1.0

Successfully pushed bundle to docker.io/lucj/tick:0.1.0. Digest is sha256:7a71d2bfb5588be0cb74cd76cc46575b58c433da1fa05b4eeccd5288b4b75bac.

It then appears next to the Docker images on the account it was pushed to:

The application is now ready to be used by anyone; it just needs to be pulled from the Docker Hub:
$ docker app pull lucj/tick:0.1.0
Before we move to the next part, we will remove the application we deployed on the Swarm cluster:
$ docker app uninstall tick
Removing service tick_chronograf
Removing service tick_influxdb
Removing service tick_kapacitor
Removing service tick_telegraf
Removing config tick_telegraf-conf
Removing network tick_default
Application “tick” uninstalled on context “default”

Deploying the Docker App on Kubernetes
We saw how easy it is to deploy a Docker App on Swarm. We will now deploy it on Kubernetes, and we’ll see it’s just as easy.
First, we set the Docker context to use Kubernetes as the orchestrator.
$ docker context use k8s-demo
k8s-demo
Current context is now “k8s-demo”

Next, we install the application with the exact same command we used to deploy it on Swarm:
$ docker app install tick.dockerapp –name tick –parameters-file tick.dockerapp/prod.yml
Waiting for the stack to be stable and running…
influxdb: Pending
chronograf: Pending
kapacitor: Pending
telegraf: Pending
telegraf: Ready
kapacitor: Ready
chronograf: Ready
influxdb: Ready

Stack tick is stable and running

Application “tick” installed on context “k8s-demo”

Using kubectl, we list the resources to make sure everything was created correctly:
$ kubectl get deploy,po,svc
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.extensions/chronograf 1/1 1 1 26s
deployment.extensions/influxdb 1/1 1 1 26s
deployment.extensions/kapacitor 1/1 1 1 26s
deployment.extensions/telegraf 1/1 1 1 26s

NAME READY STATUS RESTARTS AGE
pod/chronograf-c55797884-b7rcd 1/1 Running 0 26s
pod/influxdb-67c574845d-bcr8m 1/1 Running 0 26s
pod/kapacitor-57f6787666-82b7l 1/1 Running 0 26s
pod/telegraf-6b8648884c-xcmmx 1/1 Running 0 26s

NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/chronograf ClusterIP None <none> 55555/TCP 25s
service/chronograf-published LoadBalancer 10.104.26.162 <pending> 9001:31319/TCP 25s
service/influxdb ClusterIP None <none> 55555/TCP 26s
service/kapacitor ClusterIP None <none> 55555/TCP 26s
service/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 2d4h
service/telegraf ClusterIP None <none> 55555/TCP 26s
service/telegraf-published LoadBalancer 10.108.195.24 <pending> 9000:30684/TCP 25s

Note: The deployment on Kubernetes only works on Docker Desktop or Docker Enterprise, which run the server side controller needed to handle the stack resource.
Summary
I hope this article provides some insights on the Docker Application. The project is still quite young so breaking changes may occur before it reaches 1.0.0, but one thing that’s promising – it lets us deploy to Kubernetes without knowing much of anything about Kubernetes!
To learn more about Docker App:

Read our introductory post on Docker App and CNAB 

Find out how to access Docker App

The post Managing the TICK Stack with Docker App appeared first on Docker Blog.
Quelle: https://blog.docker.com/feed/

AWS IoT Greengrass 1.10 Now Supports Docker Containers

On November 25, 2019, AWS announced the release of AWS IoT Greengrass 1.10 allowing developers to package applications into Docker container images and deploy these to edge devices. Deploying and running Docker containers on AWS IoT Greengrass devices enables application portability across development environments, edge locations, and the cloud. Docker images can easily be stored in Docker Hub, private container registries, or with Amazon Elastic Container Registry (Amazon ECR).

Docker is committed to working with cloud service provider partners such as AWS who offer Docker-compatible on-demand container infrastructure services for both individual containers as well as multi-container apps. To make it even easier for developers to benefit from the speed of these services but without giving up app portability and infrastructure choice, Docker Hub will seamlessly integrate developers’ “build” and “share” workflows with the cloud “run” services of their choosing.
“Docker and AWS are collaborating on our shared vision of how workloads can be more easily deployed to edge devices. Docker’s industry-leading container technology including Docker Desktop and Docker Hub are integral to advancing developer workflows for modern apps and IoT solutions. Our customers can now deploy and run Docker containers seamlessly on AWS IoT Greengrass devices, enabling development teams to ship apps faster and accelerate the migration of apps from the data center to the cloud, and now to edge devices,” according to David Messina, EVP Strategic Alliances for Docker.
If you are interested in how to actually deploy a Docker container-based application to an AWS IoT Greengrass core device, AWS’ Danilo Poccia has a great blog that walks developers step-by-step through the process. Developers who are interested in learning more about how to get started with Docker technologies, you can expand your understanding of Docker and Kubernetes with these additional free and paid resources here.
The post AWS IoT Greengrass 1.10 Now Supports Docker Containers appeared first on Docker Blog.
Quelle: https://blog.docker.com/feed/

Black Friday Deals on Docker + Kubernetes Courses

In honor of Black Friday, America’s favorite shopping holiday, we’ve rounded up the best deals on Docker + Kubernetes learning materials from Docker Captains. Docker Captain is a distinction that Docker awards to select members of the community that are both experts in their field and are committed to sharing their Docker knowledge with others. 
Books:

Learn Docker in a Month of Lunches, Elton Stoneman (Save 40% with the code webdoc40).

Docker in Action Second Edition (2019), Jeff Nickeloff (Save 50% with the code tsdocker).

Manning publications is also offering half off when you spend $50 this week.

Nigel Poulton’s The Kubernetes Book and Docker Deep Dive ebook bundles is $7 (for both!) through December 1st with this link.

Self-Paced Online Courses:

All of Bret Fisher’s courses are $9.99 through Friday, November 29th. Choose from Docker Mastery, Kubernetes Mastery, Swarm Mastery, and Docker for Node.js.

Elton Stoneman has a wealth of courses, from Handling Data and Stateful Applications in Docker to Modernizing .Net Framework Apps with Docker on Pluralsight. Get 40% an annual or premium subscription through Friday November 29th.

Nick Janetakis’s Dive into Docker and Build Web Applications with Flask and Docker courses will be 50% off (no code needed) through December 2nd.

Nigel Poulton’s Kubernetes 101 course is $9.99 with the code K8S101 through Dec 1st.
And his 20 Pluralsight courses – including Docker and Kubernetes: The Big Picture; Docker Deep Dive; Getting Started with Kubernetes and more are also 40% off with an annual or premium subscription through the 29th.

Docker + Kubernetes in French:

Luc Juggery creates Docker + Kubernetes courses in French. Both his Introduction to Kubernetes and The Docker Platform courses are $9.99 through Friday November 29th.

This Thanksgiving, take advantage of leveling up your skills at a great price or check out all educational resources here.
The post Black Friday Deals on Docker + Kubernetes Courses appeared first on Docker Blog.
Quelle: https://blog.docker.com/feed/