Home  >  Article  >  System Tutorial  >  lxc exec: Explore its unique charm

lxc exec: Explore its unique charm

WBOY
WBOYforward
2023-12-30 17:25:53966browse
Introduction
Recently, I've made several improvements to lxc exec. If you don't know it, let me introduce it. lxc exec is the client tool of LXD. It uses the LXD client api to communicate with the LXD daemon and execute various programs that the user wants to execute. The following is an example of what you can use:

lxc exec 的魅力特征

One of our main goals is to make lxc exec similar to ssh, since it is the standard for running commands remotely, interactively or non-interactively. This makes doing lxc exec well a bit tricky.

1. Processing background tasks

A long-standing problem is of course how to properly handle background tasks. Here is an example of a problem with an LXD 2.7 instance:

lxc exec 的魅力特征

You can see that executing tasks in the background will cause lxc exec to fail to exit. Many commands can trigger this issue:

chb@conventiont|~ 
> lxc exec zest1 bash 
root@zest1:~# yes &
 y
 y 
 y 
 . 
 . 
 .

Nothing can save you now. yes will always write directly to stdout.

The root of the problem is that stdout is always open, but this is necessary because it is used to ensure that any data written by the process started by the user is actually read and sent back through the websocket connection we established. .

If you want to do this, run a shell session, then run a process in the background, and exit the shell immediately. Sorry, it doesn't work as expected.

The first and primitive approach is to simply close stdout once you detect that the foreground program (e.g. shell) has exited. But this is not as good as you think. This problem becomes obvious when you run fast execution programs, such as:

lxc exec -- ls -al /usr/lib

Here the lxc exec process (and the related forkexec process. But don't think about it now, just remember that Go setns() does not communicate...) will exit before all the buffered data in stdout has been read. This situation will result in truncated output, which no one wants. After trying several methods to solve the problem, including disabling pty buffering (let me tell you, it's not pretty and doesn't work as expected.) and other weird ideas, I managed to get through a few poll() "tricks" ( In a sense a "trick") solves this problem. Now you can finally run background tasks and exit completely. As shown in the picture:

lxc exec 的魅力特征

2. Report exit codes caused by signals

ssh is a great tool. But one thing I've always disliked is that ssh always reports -1, which is exit code 255, when a command run by ssh receives a signal. This is annoying when you want to understand the signal that caused the program to terminate. This is why I recently implemented the convention used by standard shells 128 n to report any exit caused by a signal, where n is defined as the semaphore that caused the executor to exit. For example, on the SIGKILL signal, you would see 128 SIGKILL = 137 (calculate the exit codes for other fatal signals as an exercise for the reader). So you can do this:

chb@conventiont|~ 
> lxc exec zest1 sleep 100

Now, send SIGKILL to the executor (not lxc exec itself, since SIGKILL is not forwardable).

kill -KILL $(pidof sleep 100)

Finally check the exit code of your program:

chb@conventiont|~
> echo $?
137

Look. This apparently only works if a) the exit code doesn't exceed the 8-bit computational barrier, and b) when the executor doesn't use 137 to indicate success (how...interesting?!). Neither argument seems very convincing to me. The former is because fatal semaphores should not exceed this range. The latter because (i) it's a user issue, (ii) these exit codes are actually retained (I think so.), and (iii) you'll have the same problem running the program locally or elsewhere.

The main advantage I see is the ability to report fine-grained exit status to the executor. Note that we do not report all program instances killed by signals. For example, when your program is able to handle SIGTERM and exit cleanly, LXD has no easy way to detect this and report that the program was killed by the signal. You will simply receive exit code 0.

3. Forward signal

This may not be very interesting (or maybe not, who knows), but I find it very useful. As you can see in the SIGKILL case, I explicitly stated that SIGKILL must be sent to the executor, not the lxc exec command itself. This is because SIGKILL cannot be handled in the program. The only thing a program can do is die, like now...like in this example...right away (you get the idea...). But the program can handle many other signals, SIGTERM, SIGHUP', and of course SIGUSR1 and SIGUSR2. Therefore, when you send a signal that can be handled by lxc exec` but not by the executor, newer versions of LXD will forward the signal to the executor. This is very convenient in scripts.

Anyway, I hope you found this little lxc exec article/gibberish useful. Enjoy LXD, it's playing with a crazy beautiful beast. Please try the online experiment: https://linuxcontainers.org/lxd/try-it/, and for developers look here: https://github.com/lxc/lxd and send us patches.

We do not require any CLA to be signed, we follow kernel style as long as there is a "Signed-off-by" line in it.


The above is the detailed content of lxc exec: Explore its unique charm. For more information, please follow other related articles on the PHP Chinese website!

Statement:
This article is reproduced at:linuxprobe.com. If there is any infringement, please contact admin@php.cn delete