docker脚本

One of the goals of Docker is to simplify what it takes to start and run applications. A way Docker tries to achieve this goal is by allowing users to create an isolated runtime environment where they don’t need complex startup scripts.

Docker的目标之一是简化启动和运行应用程序所需的时间。 Docker试图实现此目标的一种方式是允许用户创建一个不需要复杂的启动脚本的隔离的运行时环境。

For the most part, it works. Docker is simple enough that an average application can be started directly with the ENTRYPOINT instructions within the Dockerfile.

在大多数情况下,它是有效的。 码头工人是很简单的,一个普通的应用程序可直接与启动ENTRYPOINT的范围内说明Dockerfile

ENTRYPOINT ["./my-app"]

However, not every app can start up so simple.

但是,并非每个应用程序都能如此简单地启动。

It is not uncommon to require specific tasks to execute within the container environment before the application starts. These tasks could be as simple as managing secrets like Certificates/Passwords, or highly complex like an orchestrated multi-step start process.

在应用程序启动之前,要求特定任务在容器环境中执行的情况并不少见。 这些任务可以像管理证书/密码之类的机密一样简单,也可以像精心策划的多步启动过程那样高度复杂。

The reasons are numerous, and they typically all depend on both the application and the hosting environment it’s running in. The typical answer to this issue is to create ENTRYPOINT scripts.

原因很多,它们通常都取决于应用程序和运行它的主机环境。此问题的典型答案是创建ENTRYPOINT脚本。

These scripts are custom start scripts the replace the application in the ENTRYPOINT. Below is an example of a Dockerfile that uses a ENTRYPOINT script.

这些脚本是自定义启动脚本,用于替换ENTRYPOINT的应用程序。 以下是使用ENTRYPOINT脚本的Dockerfile的示例。

One common issue with these scripts is that many times, users find it challenging to pass shutdown signals to the running application. That is what this article is going to cover, how best to write scripts that don’t break shutdown signals, and why it’s so easy to get it wrong.

这些脚本的一个普遍问题是,很多时候,用户发现将关机信号传递给正在运行的应用程序具有挑战性。 这就是本文要讨论的内容,如何最好地编写不会破坏关闭信号的脚本,以及为什么这么容易弄错它。

正确编写ENTRYPOINT脚本 (Writing ENTRYPOINT scripts the right way)

Before we start delving into how to write ENTRYPOINT scripts the right way, let’s first look at how easy it is to write one the wrong way.

在开始研究如何以正确的方式编写ENTRYPOINT脚本之前,让我们首先看看以错误的方式编写一个脚本有多么容易。

On the surface, the above script looks reasonably good, it… “should” work. But it doesn’t.

从表面上看,上面的脚本看起来相当不错,它“应该”起作用。 但事实并非如此。

Our script is a pretty good example of what a ENTRYPOINT script is. It first checks for a secret file, loads the contents of that file into an environment variable defined at runtime, and then starts our application. So, where does it go wrong?

我们的脚本很好地说明了ENTRYPOINT脚本是什么。 它首先检查一个秘密文件,将该文件的内容加载到运行时定义的环境变量中,然后启动我们的应用程序。 那么,哪里出错了?

It goes wrong with how it starts the application. Currently, our script is starting our service by only running the binary. What this does, is it creates a child process of our running app.

如何启动应用程序出错。 当前,我们的脚本仅通过运行二进制文件来启动我们的服务。 这是在创建正在运行的应用程序的子进程。

It is easier to explain if we login to our running container and run ps -elf to see our processes.

如果我们登录到正在运行的容器并运行ps -elf来查看进程, ps -elf容易解释。

F S UID        PID  PPID  C PRI  NI ADDR SZ WCHAN  STIME TTY          TIME CMD
4 S root 1 0 0 80 0 - 934 - 06:43 ? 00:00:00 /bin/bash ../../docker-entrypoint.sh
4 S root 11 1 0 80 0 - 269652 - 06:43 ? 00:00:00 healthchecks-example

Within our container, we have two processes; PID 1 (parent), which is our actual entry point script, and PID 11 (child), which is our running service.

在我们的容器中,我们有两个过程; PID 1(父级)是我们的实际入口点脚本,PID 11(子级)是我们的运行服务。

When Docker attempts to stop a container, it will send the specified signal to PID 1, the process that Docker starts. Docker will completely ignore any other process running within this container. So that means when we issue a docker stop, the Docker daemon will send a SIGTERM signal to the docker-entrypoint.sh process, not to our running service.

当Docker尝试停止容器时,它将发送指定的信号给PID 1,即Docker启动的过程。 Docker将完全忽略此容器中运行的任何其他进程。 因此,这意味着当我们发出docker stop ,Docker守护进程会将SIGTERM信号发送到docker-entrypoint.sh进程,而不是发送到我们正在运行的服务。

What is also important to note is that in Unix & Linux systems, a signal sent to the parent process will never pass to the child processes. What this means is, our script will receive a signal, but our running service will not. The only reason our process stops is that when the primary process stops executing (because it received a SIGTERM), Docker will teardown the container forcefully reaping any other running processes inside of it.

还需要注意的重要一点是,在Unix和Linux系统中,发送到父进程的信号永远不会传递到子进程。 这意味着,我们的脚本将收到一个信号,但我们的运行服务不会。 我们的进程停止的唯一原因是,当主进程停止执行时(因为它收到了SIGTERM),Docker将强行拆除容器,以强夺其中的任何其他正在运行的进程。

So how do we modify our script to work with signals to shutdown our apps gracefully? Simple, we use the exec command.

那么,我们如何修改脚本以与信号一起正常关闭应用程序呢? 很简单,我们使用exec命令。

What makes the exec command special is that when used to execute a command like running our service. This command will replace the parent process with the new process. We can see this in action if we once again look at the process list from inside our container.

exec命令之所以与众不同,是因为它用于执行诸如运行我们的服务之类的命令。 此命令将用新进程替换父进程。 如果我们再次从容器内部查看流程列表,就可以看到实际的效果。

F S UID        PID  PPID  C PRI  NI ADDR SZ WCHAN  STIME TTY          TIME CMD
4 S root 1 0 0 80 0 - 288149 - 06:56 ? 00:00:00 healthchecks-example

Notice the difference? When using exec the only process running is our service. It has completely replaced our script, including taking over the process id.

注意区别吗? 使用exec ,唯一运行的进程是我们的服务。 它已完全替换了我们的脚本,包括接管了进程ID。

Now when Docker sends the SIGTERM signal to process id 1, our service will trap the SIGTERM gracefully shutting down.

现在,当Docker将SIGTERM信号发送到进程ID 1时,我们的服务将捕获SIGTERM正常关闭。

That’s it; that is the secret to writing ENTRYPOINT scripts that allow the service to shutdown gracefully. However, you may still find that even with a well-written ENTRYPOINT script, signals are still not working. The most likely cause is not within the script but the Dockerfile.

而已; 这是编写允许服务正常关闭的ENTRYPOINT脚本的秘诀。 但是,您可能仍然会发现,即使使用编写良好的ENTRYPOINT脚本,信号仍然无法正常工作。 最可能的原因不在脚本内,而在Dockerfile

确保Dockerfile正确 (Making sure the Dockerfile is correct)

While our ENTRYPOINT script is now working; there is another prevalent mistake that occurs. It’s straightforward, but it all revolves around how we use the ENTRYPOINT instruction within the Dockerfile.

现在我们的ENTRYPOINT脚本正在运行; 还有另一个普遍发生的错误。 它的简单,但是这一切都围绕着我们如何使用的ENTRYPOINT的内部指令Dockerfile

Docker allows for two methods of defining ENTRYPOINT instructions.

Docker支持两种定义ENTRYPOINT指令的方法。

ENTRYPOINT ../../docker-entrypoint.sh

The above is called the “shell” form, where the command is specified. The second form is the “exec” form, where the command and arguments are in a JSON format.

上面称为“ shell”形式,其中指定了命令。 第二种形式是“ exec”形式,其中命令和参数采用JSON格式。

ENTRYPOINT ["../../docker-entrypoint.sh"]

The difference is that when using the “shell” form, Docker will run the specified command within a sub-shell utilizing the sh -c "command" method. We can once again see this in action by looking at the process list within the running container.

区别在于,当使用“ shell”形式时,Docker将使用sh -c "command"方法在子shell中运行指定的命令。 通过查看正在运行的容器中的进程列表,我们可以再次看到这一点。

F S UID        PID  PPID  C PRI  NI ADDR SZ WCHAN  STIME TTY          TIME CMD
4 S root 1 0 0 80 0 - 597 - 07:13 ? 00:00:00 /bin/sh -c ../../docker-entrypoint.sh
4 S root 6 1 0 80 0 - 269652 - 07:13 ? 00:00:00 healthchecks-example

With the above, we can see that there are two processes once again.

通过上面的内容,我们可以看到又有两个过程。

It is important to note that even though our script is correct, using the “shell” form changes behavior. For signals to work correctly, it is vital to use the “exec” ENTRYPOINT format.

重要的是要注意,即使我们的脚本是正确的,使用“ shell”形式也会改变行为。 为了使信号正常工作,使用“ exec” ENTRYPOINT格式至关重要。

摘要 (Summary)

In this article, we explored two common mistakes people make when using ENTRYPOINT scripts with Docker. They both come down to the use of using sub-processes to start the application. If you take away nothing else, remember this. Sub-processes do not receive shutdown signals and based on how you write the ENTRYPOINT scripts and Dockerfile instruction; determines if the application starts as a sub-process.

在本文中,我们探讨了人们在Docker中使用ENTRYPOINT脚本ENTRYPOINT犯的两个错误。 他们都归结为使用子流程来启动应用程序。 如果您没有带走其他东西,请记住这一点。 子进程不接收关闭信号,而是基于您编写ENTRYPOINT脚本和Dockerfile指令的方式; 确定应用程序是否作为子进程启动。

To learn more about signals, check out my article; Signal Traps: What are they, and how to use them.

要了解有关信号的更多信息,请查看我的文章。 信号陷阱:它们是什么,以及如何使用它们

翻译自: https://medium.com/@madflojo/shutdown-signals-with-docker-entry-point-scripts-5e560f4e2d45

docker脚本

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐