Merge pull request #3085 from djs55/update-logging

Support pluggable logging systems
This commit is contained in:
Rolf Neugebauer 2018-07-07 09:21:13 +01:00 committed by GitHub
commit 29c3ef0aa0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
113 changed files with 740 additions and 720 deletions

View File

@ -33,7 +33,7 @@ kernel:
image: linuxkit/kernel:4.9.91
cmdline: "console=tty0 console=ttyS0 console=ttyAMA0"
init:
- linuxkit/init:0e4af96fecc8f752c80d41c0b7d06570cc1dc6b2
- linuxkit/init:6cc1442112980c889230b6449df09d5b48de6854
- linuxkit/runc:v0.4
- linuxkit/containerd:27a4c84cc8fab2d5ea04342546ecd20453ec99b3
services:

94
docs/logging.md Normal file
View File

@ -0,0 +1,94 @@
# Logging
By default LinuxKit will write onboot and service logs directly to files in
`/var/log` and `/var/log/onboot`.
It is tricky to write the logs to a disk or a network service as no disks
or networks are available until the `onboot` containers run. We work around
this by splitting the logging into 2 pieces:
1. `memlogd`: an in-memory circular buffer which receives logs (including
all the early `onboot` logs)
2. a log writing `service` that starts later and can download and process
the logs from `memlogd`
To use this new logging system, you should add the `memlogd` container to
the `init` block in the LinuxKit yml. On boot `memlogd` will be started
from `init.d` and it will listen on a Unix domain socket:
```
/var/run/linuxkit-external-logging.sock
```
The `init`/`service` process will look for this socket and redirect the
`stdout` and `stderr` of both `onboot` and `services` to `memlogd`.
## memlogd: an in-memory circular buffer
The `memlogd` daemon reads the logs from the `onboot` and `services` containers
and stores them together with a timestamp and the name of the originating
container in a circular buffer in memory.
The contents of the circular buffer can be read over the Unix domain socket
```
/var/run/memlogq.sock
```
The circular buffer has a fixed size (overridden by the command-line argument
`-max-lines`) and when it fills up, the oldest messages will be overwritten.
To store the logs somewhere more permanent, for example a disk or a remote
network service, a service should be added to the yaml which connects to
`memlogd` and streams the logs. The example program `logread` in the `memlogd`
package demonstrates how to do this.
### Message format
The format used to read logs is similar to [kmsg](https://www.kernel.org/doc/Documentation/ABI/testing/dev-kmsg):
```
<timestamp>,<log>;<body>
```
where `<timestamp>` is an RFC3339-formatted timestamp, `<log>` is the name of
the log (e.g. `docker-ce.out`) and `<body>` is the output. The `<log>` must
not contain the character `;`.
### Usage examples
```
/ # logread -f
2018-07-05T13:22:32Z,memlogd;memlogd started
2018-07-05T13:22:32Z,onboot.001-dhcpcd.out;eth0: waiting for carrier
2018-07-05T13:22:32Z,onboot.001-dhcpcd.err;eth0: could not detect a useable init
system
2018-07-05T13:22:32Z,onboot.001-dhcpcd.out;eth0: carrier acquired
2018-07-05T13:22:32Z,onboot.001-dhcpcd.out;DUID 00:01:00:01:22:d0:d8:18:02:50:00:00:00:02
2018-07-05T13:22:32Z,onboot.001-dhcpcd.out;eth0: IAID 00:00:00:02
2018-07-05T13:22:32Z,onboot.001-dhcpcd.out;eth0: adding address fe80::d33a:3936:
2ee4:5c8c
2018-07-05T13:22:32Z,onboot.001-dhcpcd.out;eth0: soliciting an IPv6 router
2018-07-05T13:22:32Z,onboot.001-dhcpcd.out;eth0: soliciting a DHCP lease
2018-07-05T13:22:32Z,onboot.001-dhcpcd.out;eth0: offered 192.168.65.4 from 192.1
68.65.1 `vpnkit'
2018-07-05T13:22:32Z,onboot.001-dhcpcd.out;eth0: leased 192.168.65.4 for 7200 se
conds
2018-07-05T13:22:32Z,onboot.001-dhcpcd.out;eth0: adding route to 192.168.65.0/24
2018-07-05T13:22:32Z,onboot.001-dhcpcd.out;eth0: adding default route via 192.16
8.65.1
2018-07-05T13:22:32Z,onboot.001-dhcpcd.out;exiting due to oneshot
2018-07-05T13:22:32Z,onboot.001-dhcpcd.out;dhcpcd exited
^C
```
Current issues and limitations:
- No docker logger plugin support yet - it could be nice to add support to
memlogd, so the docker container logs would also be gathered in one place
- No syslog compatibility at the moment and `/dev/log` doesnt exist. This
socket could be created to keep syslog compatibility, e.g. by using
https://github.com/mcuadros/go-syslog. Processes that require syslog should
then be able to log directly to memlogd.
- Kernel messages not read on startup yet (but can be captured with
`logwrite dmesg`)
- Currently no direct external hooks exposed - but options available that
could be added. Should also be possible to pipe output to e.g. `oklog`
from `logread` (https://github.com/oklog/oklog)

View File

@ -2,7 +2,7 @@ kernel:
image: linuxkit/kernel:4.14.53
cmdline: "console=ttyS0"
init:
- linuxkit/init:0e4af96fecc8f752c80d41c0b7d06570cc1dc6b2
- linuxkit/init:6cc1442112980c889230b6449df09d5b48de6854
- linuxkit/runc:v0.4
- linuxkit/containerd:27a4c84cc8fab2d5ea04342546ecd20453ec99b3
- linuxkit/ca-certificates:v0.4

View File

@ -2,7 +2,7 @@ kernel:
image: linuxkit/kernel:4.14.53
cmdline: "console=ttyS0"
init:
- linuxkit/init:0e4af96fecc8f752c80d41c0b7d06570cc1dc6b2
- linuxkit/init:6cc1442112980c889230b6449df09d5b48de6854
- linuxkit/runc:v0.4
- linuxkit/containerd:27a4c84cc8fab2d5ea04342546ecd20453ec99b3
- linuxkit/ca-certificates:v0.4

View File

@ -2,7 +2,7 @@ kernel:
image: linuxkit/kernel:4.14.53
cmdline: "console=tty0 console=ttyS0 console=ttyAMA0 console=ttysclp0"
init:
- linuxkit/init:0e4af96fecc8f752c80d41c0b7d06570cc1dc6b2
- linuxkit/init:6cc1442112980c889230b6449df09d5b48de6854
- linuxkit/runc:v0.4
- linuxkit/containerd:27a4c84cc8fab2d5ea04342546ecd20453ec99b3
- linuxkit/ca-certificates:v0.4

View File

@ -4,7 +4,7 @@ kernel:
cmdline: "console=ttyS0 page_poison=1"
init:
- linuxkit/vpnkit-expose-port:v0.4 # install vpnkit-expose-port and vpnkit-iptables-wrapper on host
- linuxkit/init:0e4af96fecc8f752c80d41c0b7d06570cc1dc6b2
- linuxkit/init:6cc1442112980c889230b6449df09d5b48de6854
- linuxkit/runc:v0.4
- linuxkit/containerd:27a4c84cc8fab2d5ea04342546ecd20453ec99b3
- linuxkit/ca-certificates:v0.4

View File

@ -2,7 +2,7 @@ kernel:
image: linuxkit/kernel:4.14.53
cmdline: "console=tty0 console=ttyS0 console=ttyAMA0 console=ttysclp0"
init:
- linuxkit/init:0e4af96fecc8f752c80d41c0b7d06570cc1dc6b2
- linuxkit/init:6cc1442112980c889230b6449df09d5b48de6854
- linuxkit/runc:v0.4
- linuxkit/containerd:27a4c84cc8fab2d5ea04342546ecd20453ec99b3
- linuxkit/ca-certificates:v0.4

View File

@ -2,7 +2,7 @@ kernel:
image: linuxkit/kernel:4.14.53
cmdline: "console=ttyS0"
init:
- linuxkit/init:0e4af96fecc8f752c80d41c0b7d06570cc1dc6b2
- linuxkit/init:6cc1442112980c889230b6449df09d5b48de6854
- linuxkit/runc:v0.4
- linuxkit/containerd:27a4c84cc8fab2d5ea04342546ecd20453ec99b3
- linuxkit/ca-certificates:v0.4

View File

@ -2,7 +2,7 @@ kernel:
image: linuxkit/kernel:4.14.53
cmdline: "console=tty0 console=ttyS0 console=ttyAMA0 console=ttysclp0"
init:
- linuxkit/init:0e4af96fecc8f752c80d41c0b7d06570cc1dc6b2
- linuxkit/init:6cc1442112980c889230b6449df09d5b48de6854
- linuxkit/runc:v0.4
- linuxkit/containerd:27a4c84cc8fab2d5ea04342546ecd20453ec99b3
- linuxkit/ca-certificates:v0.4

View File

@ -2,7 +2,7 @@ kernel:
image: linuxkit/kernel:4.14.53
cmdline: "console=tty0 console=ttyS0 console=ttyAMA0 console=ttysclp0"
init:
- linuxkit/init:0e4af96fecc8f752c80d41c0b7d06570cc1dc6b2
- linuxkit/init:6cc1442112980c889230b6449df09d5b48de6854
- linuxkit/runc:v0.4
- linuxkit/containerd:27a4c84cc8fab2d5ea04342546ecd20453ec99b3
- linuxkit/ca-certificates:v0.4

View File

@ -2,7 +2,7 @@ kernel:
image: linuxkit/kernel:4.14.53
cmdline: "console=tty0 console=ttyS0 console=ttyAMA0"
init:
- linuxkit/init:0e4af96fecc8f752c80d41c0b7d06570cc1dc6b2
- linuxkit/init:6cc1442112980c889230b6449df09d5b48de6854
- linuxkit/runc:v0.4
- linuxkit/containerd:27a4c84cc8fab2d5ea04342546ecd20453ec99b3
- linuxkit/ca-certificates:v0.4

30
examples/logging.yml Normal file
View File

@ -0,0 +1,30 @@
# Simple example of using an external logging service
kernel:
image: linuxkit/kernel:4.14.53
cmdline: "console=tty0 console=ttyS0 console=ttyAMA0"
init:
- linuxkit/init:6cc1442112980c889230b6449df09d5b48de6854
- linuxkit/runc:v0.4
- linuxkit/containerd:f2bc1bda1ab18146967fa1a149800aaf14bee81b
- linuxkit/ca-certificates:v0.4
- linuxkit/memlogd:883f0d46e7d3ae2d787e8acb496da115a4707cbc
onboot:
- name: sysctl
image: linuxkit/sysctl:v0.4
- name: dhcpcd
image: linuxkit/dhcpcd:v0.4
command: ["/sbin/dhcpcd", "--nobackground", "-f", "/dhcpcd.conf", "-1"]
services:
# Inside the getty type `/proc/1/root/usr/bin/logread -F` to follow the log
- name: getty
image: linuxkit/getty:44730fd0a7c59dbacf5b48b54ba33f551bcf7ef0
env:
- INSECURE=true
# A service which generates log messages for testing
- name: write-to-the-logs
image: alpine
command: ["/bin/sh", "-c", "while /bin/true; do echo hello $(date); sleep 1; done" ]
trust:
org:
- linuxkit
- library

View File

@ -2,7 +2,7 @@ kernel:
image: linuxkit/kernel:4.14.53
cmdline: "console=tty0 console=ttyS0 console=ttyAMA0"
init:
- linuxkit/init:0e4af96fecc8f752c80d41c0b7d06570cc1dc6b2
- linuxkit/init:6cc1442112980c889230b6449df09d5b48de6854
- linuxkit/runc:v0.4
- linuxkit/containerd:27a4c84cc8fab2d5ea04342546ecd20453ec99b3
onboot:

View File

@ -2,7 +2,7 @@ kernel:
image: linuxkit/kernel:4.14.53
cmdline: "console=tty0 console=ttyS0"
init:
- linuxkit/init:0e4af96fecc8f752c80d41c0b7d06570cc1dc6b2
- linuxkit/init:6cc1442112980c889230b6449df09d5b48de6854
- linuxkit/runc:v0.4
- linuxkit/containerd:27a4c84cc8fab2d5ea04342546ecd20453ec99b3
services:

View File

@ -2,7 +2,7 @@ kernel:
image: linuxkit/kernel:4.14.53
cmdline: "console=ttyS0"
init:
- linuxkit/init:0e4af96fecc8f752c80d41c0b7d06570cc1dc6b2
- linuxkit/init:6cc1442112980c889230b6449df09d5b48de6854
- linuxkit/runc:v0.4
- linuxkit/containerd:27a4c84cc8fab2d5ea04342546ecd20453ec99b3
- linuxkit/ca-certificates:v0.4

View File

@ -3,7 +3,7 @@ kernel:
cmdline: console=ttyS1
ucode: intel-ucode.cpio
init:
- linuxkit/init:0e4af96fecc8f752c80d41c0b7d06570cc1dc6b2
- linuxkit/init:6cc1442112980c889230b6449df09d5b48de6854
- linuxkit/runc:v0.4
- linuxkit/containerd:27a4c84cc8fab2d5ea04342546ecd20453ec99b3
- linuxkit/ca-certificates:v0.4

View File

@ -4,7 +4,7 @@ kernel:
image: linuxkit/kernel:4.14.53
cmdline: "console=tty0 console=ttyS0 console=ttyAMA0 console=ttysclp0"
init:
- linuxkit/init:0e4af96fecc8f752c80d41c0b7d06570cc1dc6b2
- linuxkit/init:6cc1442112980c889230b6449df09d5b48de6854
- linuxkit/runc:v0.4
- linuxkit/containerd:27a4c84cc8fab2d5ea04342546ecd20453ec99b3
onboot:

View File

@ -2,7 +2,7 @@ kernel:
image: linuxkit/kernel:4.14.53-rt
cmdline: "console=tty0"
init:
- linuxkit/init:0e4af96fecc8f752c80d41c0b7d06570cc1dc6b2
- linuxkit/init:6cc1442112980c889230b6449df09d5b48de6854
- linuxkit/runc:v0.4
- linuxkit/containerd:27a4c84cc8fab2d5ea04342546ecd20453ec99b3
- linuxkit/ca-certificates:v0.4

View File

@ -2,7 +2,7 @@ kernel:
image: linuxkit/kernel:4.14.53
cmdline: "console=tty0 console=ttyS0 console=ttyAMA0 console=ttysclp0 root=/dev/vda"
init:
- linuxkit/init:a14b7ef6115e6d56fe5bf7c40517b9e190dd4dfb
- linuxkit/init:6cc1442112980c889230b6449df09d5b48de6854
- linuxkit/runc:v0.4
- linuxkit/containerd:27a4c84cc8fab2d5ea04342546ecd20453ec99b3
- linuxkit/ca-certificates:v0.4

View File

@ -2,7 +2,7 @@ kernel:
image: linuxkit/kernel:4.14.53
cmdline: "console=tty0 console=ttyS0 console=ttyAMA0 console=ttysclp0"
init:
- linuxkit/init:0e4af96fecc8f752c80d41c0b7d06570cc1dc6b2
- linuxkit/init:6cc1442112980c889230b6449df09d5b48de6854
- linuxkit/runc:v0.4
- linuxkit/containerd:27a4c84cc8fab2d5ea04342546ecd20453ec99b3
- linuxkit/ca-certificates:v0.4

View File

@ -2,7 +2,7 @@ kernel:
image: linuxkit/kernel:4.14.53
cmdline: "console=tty0 console=ttyS0 console=ttyAMA0 console=ttysclp0"
init:
- linuxkit/init:0e4af96fecc8f752c80d41c0b7d06570cc1dc6b2
- linuxkit/init:6cc1442112980c889230b6449df09d5b48de6854
- linuxkit/runc:v0.4
- linuxkit/containerd:27a4c84cc8fab2d5ea04342546ecd20453ec99b3
- linuxkit/ca-certificates:v0.4

View File

@ -2,7 +2,7 @@ kernel:
image: linuxkit/kernel:4.9.38
cmdline: "console=tty0 console=ttyS0"
init:
- linuxkit/init:0e4af96fecc8f752c80d41c0b7d06570cc1dc6b2
- linuxkit/init:6cc1442112980c889230b6449df09d5b48de6854
- linuxkit/runc:v0.4
- linuxkit/containerd:27a4c84cc8fab2d5ea04342546ecd20453ec99b3
- linuxkit/ca-certificates:v0.4

View File

@ -2,7 +2,7 @@ kernel:
image: linuxkit/kernel:4.14.53
cmdline: "console=tty0"
init:
- linuxkit/init:0e4af96fecc8f752c80d41c0b7d06570cc1dc6b2
- linuxkit/init:6cc1442112980c889230b6449df09d5b48de6854
- linuxkit/runc:v0.4
- linuxkit/containerd:27a4c84cc8fab2d5ea04342546ecd20453ec99b3
- linuxkit/ca-certificates:v0.4

View File

@ -2,7 +2,7 @@ kernel:
image: linuxkit/kernel:4.14.53
cmdline: "console=ttyS0"
init:
- linuxkit/init:0e4af96fecc8f752c80d41c0b7d06570cc1dc6b2
- linuxkit/init:6cc1442112980c889230b6449df09d5b48de6854
- linuxkit/runc:v0.4
- linuxkit/containerd:27a4c84cc8fab2d5ea04342546ecd20453ec99b3
onboot:

View File

@ -2,7 +2,7 @@ kernel:
image: linuxkit/kernel:4.14.53
cmdline: "console=ttyS0"
init:
- linuxkit/init:0e4af96fecc8f752c80d41c0b7d06570cc1dc6b2
- linuxkit/init:6cc1442112980c889230b6449df09d5b48de6854
- linuxkit/runc:v0.4
- linuxkit/containerd:27a4c84cc8fab2d5ea04342546ecd20453ec99b3
onboot:

View File

@ -2,7 +2,7 @@ kernel:
image: linuxkit/kernel:4.14.53
cmdline: "console=ttyS0"
init:
- linuxkit/init:0e4af96fecc8f752c80d41c0b7d06570cc1dc6b2
- linuxkit/init:6cc1442112980c889230b6449df09d5b48de6854
- linuxkit/runc:v0.4
- linuxkit/containerd:27a4c84cc8fab2d5ea04342546ecd20453ec99b3
- linuxkit/ca-certificates:v0.4

View File

@ -2,7 +2,7 @@ kernel:
image: linuxkit/kernel:4.14.53
cmdline: "console=tty0 console=ttyS0 console=ttyAMA0"
init:
- linuxkit/init:0e4af96fecc8f752c80d41c0b7d06570cc1dc6b2
- linuxkit/init:6cc1442112980c889230b6449df09d5b48de6854
- linuxkit/runc:v0.4
- linuxkit/containerd:27a4c84cc8fab2d5ea04342546ecd20453ec99b3
- linuxkit/ca-certificates:v0.4

View File

@ -2,7 +2,7 @@ kernel:
image: linuxkit/kernel:4.14.53
cmdline: "console=tty0 console=ttyS0 console=ttyAMA0"
init:
- linuxkit/init:0e4af96fecc8f752c80d41c0b7d06570cc1dc6b2
- linuxkit/init:6cc1442112980c889230b6449df09d5b48de6854
- linuxkit/runc:v0.4
- linuxkit/containerd:27a4c84cc8fab2d5ea04342546ecd20453ec99b3
- linuxkit/ca-certificates:v0.4

View File

@ -5,7 +5,6 @@ import (
"encoding/json"
"flag"
"fmt"
"io/ioutil"
"os"
"path/filepath"
@ -199,17 +198,11 @@ func start(ctx context.Context, service, sock, basePath, dumpSpec string) (strin
return "", 0, "failed to create container", err
}
logger := GetLog(varLogDir)
io := func(id string) (cio.IO, error) {
stdoutFile := filepath.Join("/var/log", service+".out.log")
stderrFile := filepath.Join("/var/log", service+".err.log")
// We just need this to exist. If we cannot write to the directory,
// we'll discard output instead.
if err := ioutil.WriteFile(stdoutFile, []byte{}, 0600); err != nil {
stdoutFile = "/dev/null"
}
if err := ioutil.WriteFile(stderrFile, []byte{}, 0600); err != nil {
stderrFile = "/dev/null"
}
stdoutFile := logger.Path(service + ".out")
stderrFile := logger.Path(service + ".err")
return &logio{
cio.Config{
Stdin: "/dev/null",
@ -219,7 +212,6 @@ func start(ctx context.Context, service, sock, basePath, dumpSpec string) (strin
},
}, nil
}
task, err := ctr.NewTask(ctx, io)
if err != nil {
// Don't bother to destroy the container here.

View File

@ -0,0 +1,193 @@
package main
import (
"bufio"
"errors"
"fmt"
"io"
"net"
"os"
"path/filepath"
"strings"
"syscall"
log "github.com/sirupsen/logrus"
)
var (
errLoggingNotEnabled = errors.New("logging system not enabled")
logWriteSocket = "/var/run/linuxkit-external-logging.sock"
logReadSocket = "/var/run/memlogdq.sock"
)
const (
logDumpCommand byte = iota
)
// Log provides access to a log by path or io.WriteCloser
type Log interface {
Path(string) string // Path of the log file (may be a FIFO)
Open(string) (io.WriteCloser, error) // Opens a log stream
Dump(string) // Copies logs to the console
}
// GetLog returns the log destination we should use.
func GetLog(logDir string) Log {
// is an external logging system enabled?
if _, err := os.Stat(logWriteSocket); !os.IsNotExist(err) {
return &remoteLog{
fifoDir: "/var/run",
}
}
return &fileLog{
dir: logDir,
}
}
type fileLog struct {
dir string
}
func (f *fileLog) localPath(n string) string {
return filepath.Join(f.dir, n+".log")
}
// Path returns the name of a log file path for the named service.
func (f *fileLog) Path(n string) string {
path := f.localPath(n)
// We just need this to exist, otherwise containerd will say:
//
// ERRO[0000] failed to create task error="failed to start io pipe
// copy: containerd-shim: opening /var/log/... failed: open
// /var/log/...: no such file or directory: unknown"
file, err := os.Create(path)
if err != nil {
// If we cannot write to the directory, we'll discard output instead.
return "/dev/null"
}
_ = file.Close()
return path
}
// Open a log file for the named service.
func (f *fileLog) Open(n string) (io.WriteCloser, error) {
return os.OpenFile(f.localPath(n), os.O_WRONLY|os.O_CREATE, 0644)
}
// Dump copies logs to the console.
func (f *fileLog) Dump(n string) {
path := f.localPath(n)
if err := dumpFile(os.Stdout, path); err != nil {
fmt.Printf("Error writing %s to console: %v", path, err)
}
}
type remoteLog struct {
fifoDir string
}
// Path returns the name of a FIFO connected to the logging daemon.
func (r *remoteLog) Path(n string) string {
path := filepath.Join(r.fifoDir, n+".log")
if err := syscall.Mkfifo(path, 0600); err != nil {
return "/dev/null"
}
go func() {
// In a goroutine because Open of the FIFO will block until
// containerd opens it when the task is started.
fd, err := syscall.Open(path, syscall.O_RDONLY, 0)
if err != nil {
// Should never happen: we just created the fifo
log.Printf("failed to open fifo %s: %s", path, err)
}
defer syscall.Close(fd)
if err := sendToLogger(n, fd); err != nil {
// Should never happen: logging is enabled
log.Printf("failed to send fifo %s to logger: %s", path, err)
}
}()
return path
}
// Open a log file for the named service.
func (r *remoteLog) Open(n string) (io.WriteCloser, error) {
fds, err := syscall.Socketpair(syscall.AF_UNIX, syscall.SOCK_STREAM, 0)
if err != nil {
log.Fatal("Unable to create socketpair: ", err)
}
logFile := os.NewFile(uintptr(fds[0]), "")
if err := sendToLogger(n, fds[1]); err != nil {
return nil, err
}
return logFile, nil
}
// Dump copies logs to the console.
func (r *remoteLog) Dump(n string) {
addr := net.UnixAddr{
Name: logReadSocket,
Net: "unix",
}
conn, err := net.DialUnix("unix", nil, &addr)
if err != nil {
log.Printf("Failed to connect to logger: %s", err)
return
}
defer conn.Close()
nWritten, err := conn.Write([]byte{logDumpCommand})
if err != nil || nWritten < 1 {
log.Printf("Failed to request logs from logger: %s", err)
return
}
reader := bufio.NewReader(conn)
for {
line, err := reader.ReadString('\n')
if err == io.EOF {
return
}
if err != nil {
log.Printf("Failed to read log message: %s", err)
return
}
// a line is of the form
// <timestamp>,<log>;<body>
prefixBody := strings.SplitN(line, ";", 2)
csv := strings.Split(prefixBody[0], ",")
if len(csv) < 2 {
log.Printf("Failed to parse log message: %s", line)
continue
}
if csv[1] == n {
fmt.Print(line)
}
}
}
func sendToLogger(name string, fd int) error {
var ctlSocket int
var err error
if ctlSocket, err = syscall.Socket(syscall.AF_UNIX, syscall.SOCK_DGRAM, 0); err != nil {
return err
}
var ctlConn net.Conn
if ctlConn, err = net.FileConn(os.NewFile(uintptr(ctlSocket), "")); err != nil {
return err
}
defer ctlConn.Close()
ctlUnixConn, ok := ctlConn.(*net.UnixConn)
if !ok {
// should never happen
log.Fatal("Internal error, invalid cast.")
}
raddr := net.UnixAddr{Name: logWriteSocket, Net: "unixgram"}
oobs := syscall.UnixRights(fd)
_, _, err = ctlUnixConn.WriteMsgUnix([]byte(name), oobs, &raddr)
if err != nil {
return errLoggingNotEnabled
}
return nil
}

View File

@ -62,6 +62,8 @@ func runcInit(rootPath, serviceType string) int {
log.Fatalf("Cannot create log directory %s: %v", logDir, err)
}
logger := GetLog(logDir)
for _, file := range files {
name := file.Name()
path := filepath.Join(rootPath, name)
@ -76,23 +78,19 @@ func runcInit(rootPath, serviceType string) int {
pidfile := filepath.Join(tmpdir, name)
cmd := exec.Command(runcBinary, "create", "--bundle", path, "--pid-file", pidfile, name)
// stream stdout and stderr to respective files
// ideally we want to use io.MultiWriter here, sending one stream to stdout/stderr, another to the files
// however, this hangs if we do, due to a runc bug, see https://github.com/opencontainers/runc/issues/1721#issuecomment-366315563
// once that is fixed, this can be cleaned up
stdoutFile := filepath.Join(logDir, serviceType+"."+name+".out.log")
stdout, err := os.OpenFile(stdoutFile, os.O_WRONLY|os.O_CREATE, 0644)
stdoutLog := serviceType + "." + name + ".out"
stdout, err := logger.Open(stdoutLog)
if err != nil {
log.Printf("Error opening stdout log file: %v", err)
log.Printf("Error opening stdout log connection: %v", err)
status = 1
continue
}
defer stdout.Close()
stderrFile := filepath.Join(logDir, serviceType+"."+name+".err.log")
stderr, err := os.OpenFile(stderrFile, os.O_WRONLY|os.O_CREATE, 0644)
stderrLog := serviceType + "." + name + ".err"
stderr, err := logger.Open(stderrLog)
if err != nil {
log.Printf("Error opening stderr log file: %v", err)
log.Printf("Error opening stderr log connection: %v", err)
status = 1
continue
}
@ -152,13 +150,11 @@ func runcInit(rootPath, serviceType string) int {
cleanup(path)
_ = os.Remove(pidfile)
// dump the log file outputs to os.Stdout/os.Stderr
if err = dumpFile(os.Stdout, stdoutFile); err != nil {
log.Printf("Error writing stdout of onboot service %s to console: %v", name, err)
}
if err = dumpFile(os.Stderr, stderrFile); err != nil {
log.Printf("Error writing stderr of onboot service %s to console: %v", name, err)
}
// ideally we want to use io.MultiWriter here, sending one stream to stdout/stderr, another to the log
// however, this hangs if we do, due to a runc bug, see https://github.com/opencontainers/runc/issues/1721#issuecomment-366315563
// once that is fixed, this can be cleaned up
logger.Dump(stdoutLog)
logger.Dump(stderrLog)
}
_ = os.RemoveAll(tmpdir)

19
pkg/memlogd/Dockerfile Normal file
View File

@ -0,0 +1,19 @@
FROM linuxkit/alpine:1b05307ae8152e3d38f79e297b0632697a30c65c AS build
RUN apk add --no-cache go musl-dev
ENV GOPATH=/go PATH=$PATH:/go/bin
COPY cmd/ /go/src/
RUN go-compile.sh /go/src/memlogd
RUN go-compile.sh /go/src/logread
RUN go-compile.sh /go/src/logwrite
FROM scratch
ENTRYPOINT []
CMD []
WORKDIR /
COPY --from=build /go/bin/memlogd usr/bin/memlogd
COPY --from=build /go/bin/logread usr/bin/logread
COPY --from=build /go/bin/logwrite usr/bin/logwrite
# We'll start from init.d
COPY etc/ /etc/

3
pkg/memlogd/build.yml Normal file
View File

@ -0,0 +1,3 @@
image: memlogd
binds:
- /var/run:/var/run

View File

@ -20,12 +20,15 @@ func main() {
var follow bool
var dumpFollow bool
flag.StringVar(&socketPath, "socket", "/tmp/memlogdq.sock", "memlogd log query socket")
flag.StringVar(&socketPath, "socket", "/var/run/memlogdq.sock", "memlogd log query socket")
flag.BoolVar(&dumpFollow, "F", false, "dump log, then follow")
flag.BoolVar(&follow, "f", false, "follow log buffer")
flag.Parse()
addr := net.UnixAddr{socketPath, "unix"}
addr := net.UnixAddr{
Name: socketPath,
Net: "unix",
}
conn, err := net.DialUnix("unix", nil, &addr)
if err != nil {
panic(err)

View File

@ -37,7 +37,7 @@ func main() {
var serverSocket string
var name string
flag.StringVar(&serverSocket, "socket", "/tmp/memlogd.sock", "socket to pass fd's to memlogd")
flag.StringVar(&serverSocket, "socket", "/var/run/linuxkit-external-logging.sock", "socket to pass fd's to memlogd")
flag.StringVar(&name, "n", "", "name of sender, defaults to first argument if left blank")
flag.Parse()
args := flag.Args()

View File

@ -11,7 +11,8 @@ import (
"log"
"net"
"os"
"sync"
"os/exec"
"strings"
"syscall"
"time"
)
@ -36,14 +37,13 @@ const (
)
type queryMessage struct {
conn *net.UnixConn
conn net.Conn
mode logMode
}
type connListener struct {
conn *net.UnixConn
cond *sync.Cond // condition and mutex used to notify listeners of more data
buffer bytes.Buffer
conn net.Conn
output chan *logEntry
err error
exitOnEOF bool // exit instead of blocking if no more data in read buffer
}
@ -56,57 +56,20 @@ func doLog(logCh chan logEntry, msg string) {
func logQueryHandler(l *connListener) {
defer l.conn.Close()
data := make([]byte, 0xffff)
l.cond.L.Lock()
for {
var n, remaining int
var rerr, werr error
for rerr == nil && werr == nil {
if n, rerr = l.buffer.Read(data); n == 0 { // process data before checking error
break // exit read loop to wait for more data
for msg := range l.output {
_, err := io.Copy(l.conn, strings.NewReader(msg.String()+"\n"))
if err != nil {
l.err = err
return
}
l.cond.L.Unlock()
remaining = n
w := data
for remaining > 0 && werr == nil {
w = data[:remaining]
n, werr = l.conn.Write(w)
w = w[n:]
remaining = remaining - n
}
l.cond.L.Lock()
}
// check errors
if werr != nil {
l.err = werr
l.cond.L.Unlock()
break
}
if rerr != nil && rerr != io.EOF { // EOF is ok, just wait for more data
l.err = rerr
l.cond.L.Unlock()
break
}
if l.exitOnEOF && rerr == io.EOF { // ... unless we should exit on EOF
l.err = nil
l.cond.L.Unlock()
break
}
l.cond.Wait() // unlock and wait for more data
}
}
func (msg *logEntry) String() string {
return fmt.Sprintf("%s %s %s", msg.time.Format(time.RFC3339), msg.source, msg.msg)
return fmt.Sprintf("%s,%s;%s", msg.time.Format(time.RFC3339), msg.source, msg.msg)
}
func ringBufferHandler(ringSize int, logCh chan logEntry, queryMsgChan chan queryMessage) {
func ringBufferHandler(ringSize, chanSize int, logCh chan logEntry, queryMsgChan chan queryMessage) {
// Anything that interacts with the ring buffer goes through this handler
ring := ring.New(ringSize)
listeners := list.New()
@ -128,10 +91,11 @@ func ringBufferHandler(ringSize int, logCh chan logEntry, queryMsgChan chan quer
remove = append(remove, e)
continue
}
l.cond.L.Lock()
l.buffer.WriteString(fmt.Sprintf("%s\n", msg.String()))
l.cond.L.Unlock()
l.cond.Signal()
select {
case l.output <- &msg:
default:
// channel is full so drop message
}
}
if len(remove) > 0 { // remove listeners that returned errors
for _, e := range remove {
@ -142,20 +106,31 @@ func ringBufferHandler(ringSize int, logCh chan logEntry, queryMsgChan chan quer
}
case msg := <-queryMsgChan:
l := connListener{conn: msg.conn, cond: sync.NewCond(&sync.Mutex{}), err: nil, exitOnEOF: (msg.mode == logDump)}
listeners.PushBack(&l)
l := connListener{
conn: msg.conn,
output: make(chan *logEntry, chanSize),
err: nil,
exitOnEOF: (msg.mode == logDump),
}
go logQueryHandler(&l)
if msg.mode == logDumpFollow || msg.mode == logFollow {
// register for future logs
listeners.PushBack(&l)
}
if msg.mode == logDumpFollow || msg.mode == logDump {
l.cond.L.Lock()
// fill with current data in buffer
ring.Do(func(f interface{}) {
if msg, ok := f.(logEntry); ok {
s := fmt.Sprintf("%s\n", msg.String())
l.buffer.WriteString(s)
select {
case l.output <- &msg:
default:
// channel is full so drop message
}
}
})
l.cond.L.Unlock()
l.cond.Signal() // signal handler that more data is available
}
if msg.mode == logDump {
close(l.output)
}
}
}
@ -245,6 +220,23 @@ func readLogFromFd(maxLineLen int, fd int, source string, logCh chan logEntry) {
}
}
func loggingRequestHandler(lineMaxLength int, logCh chan logEntry, fdMsgChan chan fdMessage) {
for true {
select {
case msg := <-fdMsgChan: // incoming fd
if strings.Contains(msg.name, ";") {
// The log message spec bans ";" in the log names
doLog(logCh, fmt.Sprintf("ERROR: cannot register log with name '%s' as it contains ;", msg.name))
if err := syscall.Close(msg.fd); err != nil {
doLog(logCh, fmt.Sprintf("ERROR: failed to close fd: %s", err))
}
continue
}
go readLogFromFd(lineMaxLength, msg.fd, msg.name, logCh)
}
}
}
func main() {
var err error
@ -254,19 +246,23 @@ func main() {
var passedLogFD int
var linesInBuffer int
var lineMaxLength int
var daemonize bool
flag.StringVar(&socketQueryPath, "socket-query", "/tmp/memlogdq.sock", "unix domain socket for responding to log queries. Overridden by -fd-query")
flag.StringVar(&socketLogPath, "socket-log", "/tmp/memlogd.sock", "unix domain socket to listen for new fds to add to log. Overridden by -fd-log")
flag.StringVar(&socketQueryPath, "socket-query", "/var/run/memlogdq.sock", "unix domain socket for responding to log queries. Overridden by -fd-query")
flag.StringVar(&socketLogPath, "socket-log", "/var/run/linuxkit-external-logging.sock", "unix domain socket to listen for new fds to add to log. Overridden by -fd-log")
flag.IntVar(&passedLogFD, "fd-log", -1, "an existing SOCK_DGRAM socket for receiving fd's. Overrides -socket-log.")
flag.IntVar(&passedQueryFD, "fd-query", -1, "an existing SOCK_STREAM for receiving log read requets. Overrides -socket-query.")
flag.IntVar(&linesInBuffer, "max-lines", 5000, "Number of log lines to keep in memory")
flag.IntVar(&lineMaxLength, "max-line-len", 1024, "Maximum line length recorded. Additional bytes are dropped.")
flag.BoolVar(&daemonize, "daemonize", false, "Bind sockets and then daemonize.")
flag.Parse()
var connLogFd *net.UnixConn
if passedLogFD == -1 { // no fd on command line, use socket path
addr := net.UnixAddr{socketLogPath, "unixgram"}
addr := net.UnixAddr{
Name: socketLogPath,
Net: "unixgram",
}
if connLogFd, err = net.ListenUnixgram("unixgram", &addr); err != nil {
log.Fatal("Unable to open socket: ", err)
}
@ -282,7 +278,10 @@ func main() {
var connQuery *net.UnixListener
if passedQueryFD == -1 { // no fd on command line, use socket path
addr := net.UnixAddr{socketQueryPath, "unix"}
addr := net.UnixAddr{
Name: socketQueryPath,
Net: "unix",
}
if connQuery, err = net.ListenUnix("unix", &addr); err != nil {
log.Fatal("Unable to open socket: ", err)
}
@ -296,20 +295,40 @@ func main() {
}
defer connQuery.Close()
if daemonize {
child := exec.Command(os.Args[0],
"-fd-log", "3", // connLogFd in ExtraFiles below
"-fd-query", "4", // connQuery in ExtraFiles below
"-max-lines", fmt.Sprintf("%d", linesInBuffer),
"-max-line-len", fmt.Sprintf("%d", lineMaxLength),
)
connLogFile, err := connLogFd.File()
if err != nil {
log.Fatalf("The -fd-log cannot be represented as a *File: %s", err)
}
connQueryFile, err := connQuery.File()
if err != nil {
log.Fatalf("The -fd-query cannot be represented as a *File: %s", err)
}
child.ExtraFiles = append(child.ExtraFiles, connLogFile, connQueryFile)
if err := child.Start(); err != nil {
log.Fatalf("Failed to re-exec: %s", err)
}
os.Exit(0)
}
logCh := make(chan logEntry)
fdMsgChan := make(chan fdMessage)
queryMsgChan := make(chan queryMessage)
// receive fds from the logging Unix domain socket and send on fdMsgChan
go receiveFdHandler(connLogFd, logCh, fdMsgChan)
// receive fds from the querying Unix domain socket and send on queryMsgChan
go receiveQueryHandler(connQuery, logCh, queryMsgChan)
go ringBufferHandler(linesInBuffer, logCh, queryMsgChan)
// process both log messages and queries
go ringBufferHandler(linesInBuffer, linesInBuffer, logCh, queryMsgChan)
doLog(logCh, "memlogd started")
for true {
select {
case msg := <-fdMsgChan: // incoming fd
go readLogFromFd(lineMaxLength, msg.fd, msg.name, logCh)
}
}
loggingRequestHandler(lineMaxLength, logCh, fdMsgChan)
}

View File

@ -0,0 +1,198 @@
package main
import (
"bufio"
"io"
"log"
"net"
"os"
"strings"
"syscall"
"testing"
"time"
)
func TestNonblock(t *testing.T) {
// Test that writes to the logger don't block because it is full
linesInBuffer := 10
logCh := make(chan logEntry)
queryMsgChan := make(chan queryMessage)
go ringBufferHandler(linesInBuffer, linesInBuffer, logCh, queryMsgChan)
// Overflow the log to make sure it doesn't block
for i := 0; i < 2*linesInBuffer; i++ {
select {
case logCh <- logEntry{time: time.Now(), source: "memlogd", msg: "hello TestNonblock"}:
continue
case <-time.After(time.Second):
t.Errorf("write to the logger blocked for over 1s after %d (size was set to %d)", i, linesInBuffer)
}
}
}
func TestFinite(t *testing.T) {
// Test that the logger doesn't store more than its configured maximum size
linesInBuffer := 10
logCh := make(chan logEntry)
queryMsgChan := make(chan queryMessage)
go ringBufferHandler(linesInBuffer, linesInBuffer, logCh, queryMsgChan)
// Overflow the log by 2x
for i := 0; i < 2*linesInBuffer; i++ {
logCh <- logEntry{time: time.Now(), source: "memlogd", msg: "hello TestFinite"}
}
a, b := loopback()
defer a.Close()
defer b.Close()
queryM := queryMessage{
conn: a,
mode: logDump,
}
queryMsgChan <- queryM
r := bufio.NewReader(b)
count := 0
for {
_, err := r.ReadString('\n')
if err == io.EOF {
break
}
if err != nil {
log.Fatalf("Unexpected error reading from socket: %s", err)
}
count++
}
if linesInBuffer != count {
t.Errorf("Read %d lines but expected %d", count, linesInBuffer)
}
}
func TestFinite2(t *testing.T) {
// Test that the query connection doesn't store more than the configured
// maximum size.
linesInBuffer := 10
// the output buffer size will be 1/2 of the ring
outputBufferSize := linesInBuffer / 2
logCh := make(chan logEntry)
queryMsgChan := make(chan queryMessage)
go ringBufferHandler(linesInBuffer, outputBufferSize, logCh, queryMsgChan)
// fill the ring
for i := 0; i < linesInBuffer; i++ {
logCh <- logEntry{time: time.Now(), source: "memlogd", msg: "hello TestFinite2"}
}
a, b := loopback()
defer a.Close()
defer b.Close()
queryM := queryMessage{
conn: a,
mode: logDump,
}
queryMsgChan <- queryM
// since the ring won't fit in the output buffer some should be dropped
r := bufio.NewReader(b)
count := 0
for {
_, err := r.ReadString('\n')
if err == io.EOF {
break
}
if err != nil {
log.Fatalf("Unexpected error reading from socket: %s", err)
}
count++
}
if count != outputBufferSize {
t.Errorf("Read %d lines but expected %d", count, outputBufferSize)
}
}
func TestGoodName(t *testing.T) {
// Test that the source names can't contain ";"
linesInBuffer := 10
logCh := make(chan logEntry)
fdMsgChan := make(chan fdMessage)
queryMsgChan := make(chan queryMessage)
go ringBufferHandler(linesInBuffer, linesInBuffer, logCh, queryMsgChan)
go loggingRequestHandler(80, logCh, fdMsgChan)
fds, err := syscall.Socketpair(syscall.AF_UNIX, syscall.SOCK_STREAM, 0)
if err != nil {
log.Fatal("Unable to create socketpair: ", err)
}
a := fdToConn(fds[0])
b := fdToConn(fds[1])
defer a.Close()
defer b.Close()
// defer close fds
fdMsgChan <- fdMessage{
name: "semi-colons are banned;",
fd: fds[0],
}
// although the fd should be rejected my memlogd the Write should be buffered
// by the kernel and not block.
if _, err := b.Write([]byte("hello\n")); err != nil {
log.Fatalf("Failed to write log message: %s", err)
}
c, d := loopback()
defer c.Close()
defer d.Close()
// this log should not be in the ring because the connection was rejected.
queryM := queryMessage{
conn: c,
mode: logDumpFollow,
}
queryMsgChan <- queryM
// The error log is generated asynchronously. It should be fast. On error time out
// after 5s.
d.SetDeadline(time.Now().Add(5 * time.Second))
r := bufio.NewReader(d)
for {
line, err := r.ReadString('\n')
if err == io.EOF {
break
}
if err != nil {
log.Fatalf("Unexpected error reading from socket: %s", err)
}
if strings.Contains(line, "ERROR: cannot register log") {
return
}
}
t.Fatal("Failed to read error message when registering a log with a ;")
}
// caller must close fd themselves: closing the net.Conn will not close fd.
func fdToConn(fd int) net.Conn {
f := os.NewFile(uintptr(fd), "")
c, err := net.FileConn(f)
if err != nil {
log.Fatal("Unable to create net.Conn from file descriptor: ", err)
}
return c
}
func loopback() (net.Conn, net.Conn) {
fds, err := syscall.Socketpair(syscall.AF_UNIX, syscall.SOCK_STREAM, 0)
if err != nil {
log.Fatal("Unable to create socketpair: ", err)
}
a := fdToConn(fds[0])
b := fdToConn(fds[1])
// net.Conns are independent of the fds, so we must close the fds now.
if err := syscall.Close(fds[0]); err != nil {
log.Fatal("Unable to close socketpair fd: ", err)
}
if err := syscall.Close(fds[1]); err != nil {
log.Fatal("Unable to close socketpair fd: ", err)
}
return a, b
}

View File

@ -16,8 +16,8 @@ func main() {
var memlogdBundle string
var pidFile string
var detach bool
flag.StringVar(&socketLogPath, "socket-log", "/tmp/memlogd.sock", "path to fd logging socket. Created and passed to logging container. Existing socket will be removed.")
flag.StringVar(&socketQueryPath, "socket-query", "/tmp/memlogdq.sock", "path to query socket. Created and passed to logging container. Existing socket will be removed.")
flag.StringVar(&socketLogPath, "socket-log", "/var/run/linuxkit-external-logging.sock", "path to fd logging socket. Created and passed to logging container. Existing socket will be removed.")
flag.StringVar(&socketQueryPath, "socket-query", "/var/run/memlogdq.sock", "path to query socket. Created and passed to logging container. Existing socket will be removed.")
flag.StringVar(&memlogdBundle, "bundle", "/containers/init/memlogd", "runc bundle with memlogd")
flag.StringVar(&pidFile, "pid-file", "/run/memlogd.pid", "path to pid file")
flag.BoolVar(&detach, "detach", true, "detach from subprocess")

View File

@ -0,0 +1,3 @@
#!/bin/sh
/usr/bin/memlogd -daemonize

View File

@ -2,7 +2,7 @@ kernel:
image: linuxkit/kernel-clear-containers:4.9.x
cmdline: "root=/dev/pmem0p1 rootflags=dax,data=ordered,errors=remount-ro rw rootfstype=ext4 tsc=reliable no_timer_check rcupdate.rcu_expedited=1 i8042.direct=1 i8042.dumbkbd=1 i8042.nopnp=1 i8042.noaux=1 noreplace-smp reboot=k panic=1 console=hvc0 console=hvc1 initcall_debug iommu=off quiet cryptomgr.notests page_poison=on"
init:
- linuxkit/init:0e4af96fecc8f752c80d41c0b7d06570cc1dc6b2
- linuxkit/init:6cc1442112980c889230b6449df09d5b48de6854
onboot:
- name: sysctl
image: mobylinux/sysctl:2cf2f9d5b4d314ba1bfc22b2fe931924af666d8c

View File

@ -2,7 +2,7 @@ kernel:
image: linuxkit/kernel:4.14.53
cmdline: "console=ttyS0 page_poison=1"
init:
- linuxkit/init:0e4af96fecc8f752c80d41c0b7d06570cc1dc6b2
- linuxkit/init:6cc1442112980c889230b6449df09d5b48de6854
- linuxkit/runc:v0.4
- linuxkit/containerd:27a4c84cc8fab2d5ea04342546ecd20453ec99b3
- linuxkit/ca-certificates:v0.4

View File

@ -2,7 +2,7 @@ kernel:
image: linuxkit/kernel:4.14.53
cmdline: "console=ttyS0 page_poison=1"
init:
- linuxkit/init:0e4af96fecc8f752c80d41c0b7d06570cc1dc6b2
- linuxkit/init:6cc1442112980c889230b6449df09d5b48de6854
- linuxkit/runc:v0.4
- linuxkit/containerd:27a4c84cc8fab2d5ea04342546ecd20453ec99b3
- linuxkit/ca-certificates:v0.4

View File

@ -2,7 +2,7 @@ kernel:
image: linuxkit/kernel-ima:4.11.1-186dd3605ee7b23214850142f8f02b4679dbd148
cmdline: "console=ttyS0 console=tty0 page_poison=1 ima_appraise=enforce_ns"
init:
- linuxkit/init:0e4af96fecc8f752c80d41c0b7d06570cc1dc6b2
- linuxkit/init:6cc1442112980c889230b6449df09d5b48de6854
- linuxkit/runc:v0.4
- linuxkit/containerd:27a4c84cc8fab2d5ea04342546ecd20453ec99b3
- linuxkit/ca-certificates:v0.4

View File

@ -2,7 +2,7 @@ kernel:
image: mobylinux/kernel-landlock:4.9.x
cmdline: "console=ttyS0 page_poison=1"
init:
- linuxkit/init:0e4af96fecc8f752c80d41c0b7d06570cc1dc6b2
- linuxkit/init:6cc1442112980c889230b6449df09d5b48de6854
- mobylinux/runc:b0fb122e10dbb7e4e45115177a61a3f8d68c19a9
- mobylinux/containerd:18eaf72f3f4f9a9f29ca1951f66df701f873060b
- mobylinux/ca-certificates:eabc5a6e59f05aa91529d80e9a595b85b046f935

View File

@ -1,54 +0,0 @@
### Logging tools
Experimental logging tools for linuxkit.
This project currently provides three tools for system logs; `logwrite`, `logread` and `memlogd` (+ `startmemlogd` to run `memlogd` with `runc`).
`memlogd` is the daemon that keeps logs in a circular buffer in memory. It is started automatically by `init`/`startmemlogd` in a runc container. It is passed two sockets - one that allows clients to dump/follow the logs and one that can be used to send open file descriptors to `memlogd`. When `memlogd` receives a file descriptor it will read from the file descriptor and timestamp and append the content to the in-memory log until the file is closed.
`logwrite` executes a command and will send stderr and stdout to `memlogd`. It does this by opening a socketpair for stdout and stderr and then sends the file descriptors to memlogd, before executing a specified command. Output is also sent to normal stderr/stdin. For example, `logwrite ls` will show the output both in the console and record it in the logs.
`logread` connects to memlogd and dumps the ring buffer. Parameters `-f` and `-F` can be used to follow the logs and disable the initial log dump (it behaves similar to busybox `logread`)
Init is modified to run all `onboot` and `service` containers wrapped in`logwrite` and to run `/usr/bin/startmemlogd`.
New sockets:
`/tmp/memlogd.sock` — sock_dgram which accepts an fd and a null-terminated source description
`/tmp/memlogdq.sock` — sock_stream to ask to dump/follow logs
Usage examples:
```
/ # logread -f
2017-04-15T15:37:37Z memlogd memlogd started
2017-04-15T15:37:37Z 002-dhcpcd.stdout eth0: waiting for carrier
2017-04-15T15:37:37Z 002-dhcpcd.stdout eth0: carrier acquired
2017-04-15T15:37:37Z 002-dhcpcd.stdout DUID 00:01:00:01:20:84:fa:c1:02:50:00:00:00:24
2017-04-15T15:37:37Z 002-dhcpcd.stdout eth0: IAID 00:00:00:24
2017-04-15T15:37:37Z 002-dhcpcd.stdout eth0: adding address fe80::84e3:ca52:2590:fe80
2017-04-15T15:37:37Z 002-dhcpcd.stdout eth0: soliciting an IPv6 router
2017-04-15T15:37:37Z 002-dhcpcd.stdout eth0: soliciting a DHCP lease
2017-04-15T15:37:37Z 002-dhcpcd.stdout eth0: offered 192.168.65.37 from 192.168.65.1 `vpnkit'
2017-04-15T15:37:37Z 002-dhcpcd.stdout eth0: leased 192.168.65.37 for 7199 seconds
2017-04-15T15:37:37Z 002-dhcpcd.stdout eth0: adding route to 192.168.65.0/24
2017-04-15T15:37:37Z 002-dhcpcd.stdout eth0: adding default route via 192.168.65.1
2017-04-15T15:37:37Z 002-dhcpcd.stdout exiting due to oneshot
2017-04-15T15:37:37Z 002-dhcpcd.stdout dhcpcd exited
2017-04-15T15:37:37Z rngd.stderr Unable to open file: /dev/tpm0
^C
/ # logwrite echo testing123
testing123
/ # logread | tail -n1
2017-04-15T15:37:45Z echo.stdout testing123
/ # echo -en "GET / HTTP/1.0\n\n" | nc localhost 80 > /dev/null
/ # logread | grep nginx
2017-04-15T15:42:40Z nginx.stdout 127.0.0.1 - - [15/Apr/2017:15:42:40 +0000] "GET / HTTP/1.0" 200 612 "-" "-" "-"
```
Current issues and limitations:
- The moby tool only supports onboot and service containers. `memlogd` runs as a special container that is managed by init, as it needs fds created in advance. To work around this a memlogd container is exported during build. The init-section in the yml is used to extract it to `/containers/init/memlogd` with a pre-created `config.json`.
- No docker logger plugin support yet - it could be nice to add support to memlogd, so the docker container logs would also be gathered in one place
- No syslog compatibility at the moment and `/dev/log` doesnt exist. This socket could be created to keep syslog compatibility, e.g. by using https://github.com/mcuadros/go-syslog. Processes that require syslog should then be able to log directly to memlogd.
- Kernel messages not read on startup yet (but can be captured with `logwrite dmesg`)
- Currently no direct external hooks exposed - but options available that could be added. Should also be possible to pipe output to e.g. `oklog` from `logread` (https://github.com/oklog/oklog)

View File

@ -1,33 +0,0 @@
kernel:
image: linuxkit/kernel:4.14.53
cmdline: "console=ttyS0 console=tty0 page_poison=1"
init:
- linuxkit/init:0e4af96fecc8f752c80d41c0b7d06570cc1dc6b2
- linuxkit/runc:v0.4
- linuxkit/containerd:27a4c84cc8fab2d5ea04342546ecd20453ec99b3
- linuxkit/ca-certificates:v0.4
- linuxkit/memlogd:9b5834189f598f43c507f6938077113906f51012
onboot:
- name: sysctl
image: linuxkit/sysctl:v0.4
- name: dhcpcd
image: linuxkit/dhcpcd:1fe0db6b1eb7bcb1e4823e61e08afe6d48af7d16
command: ["/sbin/dhcpcd", "--nobackground", "-f", "/dhcpcd.conf", "-1"]
services:
- name: rngd
image: linuxkit/rngd:v0.4
- name: nginx
image: nginx:1.13.8-alpine
capabilities:
- CAP_NET_BIND_SERVICE
- CAP_CHOWN
- CAP_SETUID
- CAP_SETGID
- CAP_DAC_OVERRIDE
files:
- path: etc/docker/daemon.json
contents: '{"debug": true}'
trust:
org:
- linuxkit
- library

View File

@ -1,2 +0,0 @@
sbin/
usr/

View File

@ -1,6 +0,0 @@
# Use sha256 here to get a fixed version
FROM alpine:edge@sha256:99588bc8883c955c157d18fc3eaa4a3c1400c223e6c7cabca5f600a3e9f8d5cd
ENTRYPOINT []
CMD []
WORKDIR /
COPY . ./

View File

@ -1,14 +0,0 @@
.PHONY: tag push
default: push
IMAGE=init
DEPS=Dockerfile init $(wildcard etc/*) $(wildcard etc/init.d/*)
HASH?=$(shell git ls-tree HEAD -- ../$(notdir $(CURDIR)) | awk '{print $$3}')
tag: $(DEPS)
docker build --no-cache --network=none -t linuxkit/$(IMAGE):$(HASH) .
push: tag
docker pull linuxkit/$(IMAGE):$(HASH) || \
docker push linuxkit/$(IMAGE):$(HASH)

View File

@ -1,9 +0,0 @@
#!/bin/sh
# bring up containerd
ulimit -n 1048576
ulimit -p unlimited
printf "\nStarting containerd\n"
mkdir -p /var/log
exec /usr/bin/containerd

View File

@ -1,36 +0,0 @@
#!/bin/sh
# start memlogd container
/usr/bin/startmemlogd
# start onboot containers, run to completion
if [ -d /containers/onboot ]
then
for f in $(find /containers/onboot -mindepth 1 -maxdepth 1 | sort)
do
base="$(basename $f)"
/bin/mount --bind "$f/rootfs" "$f/rootfs"
mount -o remount,rw "$f/rootfs"
/usr/bin/logwrite -n "$(basename $f)" /usr/bin/runc run --bundle "$f" "$(basename $f)"
printf " - $base\n"
done
fi
# start service containers
if [ -d /containers/services ]
then
for f in $(find /containers/services -mindepth 1 -maxdepth 1 | sort)
do
base="$(basename $f)"
/bin/mount --bind "$f/rootfs" "$f/rootfs"
mount -o remount,rw "$f/rootfs"
log="/var/log/$base.log"
/usr/bin/logwrite -n "$(basename $f)" ctr run --runtime-config "$f/config.json" --rootfs "$f/rootfs" --id "$(basename $f)" </dev/null 2>$log >$log &
printf " - $base\n"
done
fi
wait

View File

@ -1,112 +0,0 @@
#!/bin/sh
# mount filesystems
mount -n -t proc proc /proc -o nodev,nosuid,noexec,relatime
mount -n -t tmpfs tmpfs /run -o nodev,nosuid,noexec,relatime,size=10%,mode=755
mount -n -t tmpfs tmpfs /tmp -o nodev,nosuid,noexec,relatime,size=10%,mode=1777
# mount devfs
mount -n -t devtmpfs dev /dev -o nosuid,noexec,relatime,size=10m,nr_inodes=248418,mode=755
# devices
[ -c /dev/console ] || mknod -m 600 /dev/console c 5 1
[ -c /dev/tty1 ] || mknod -m 620 /dev/tty1 c 4 1
[ -c /dev/tty ] || mknod -m 666 /dev/tty c 5 0
[ -c /dev/null ] || mknod -m 666 /dev/null c 1 3
[ -c /dev/kmsg ] || mknod -m 660 /dev/kmsg c 1 11
# extra symbolic links not provided by default
[ -e /dev/fd ] || ln -snf /proc/self/fd /dev/fd
[ -e /dev/stdin ] || ln -snf /proc/self/fd/0 /dev/stdin
[ -e /dev/stdout ] || ln -snf /proc/self/fd/1 /dev/stdout
[ -e /dev/stderr ] || ln -snf /proc/self/fd/2 /dev/stderr
[ -e /proc/kcore ] && ln -snf /proc/kcore /dev/core
# devfs filesystems
mkdir -p -m 1777 /dev/mqueue
mkdir -p -m 1777 /dev/shm
mkdir -p -m 0755 /dev/pts
mount -n -t mqueue -o noexec,nosuid,nodev mqueue /dev/mqueue
mount -n -t tmpfs -o noexec,nosuid,nodev,mode=1777 shm /dev/shm
mount -n -t devpts -o noexec,nosuid,gid=5,mode=0620 devpts /dev/pts
# mount sysfs
sysfs_opts=nodev,noexec,nosuid
mount -n -t sysfs -o ${sysfs_opts} sysfs /sys
[ -d /sys/kernel/security ] && mount -n -t securityfs -o ${sysfs_opts} securityfs /sys/kernel/security
[ -d /sys/kernel/debug ] && mount -n -t debugfs -o ${sysfs_opts} debugfs /sys/kernel/debug
[ -d /sys/kernel/config ] && mount -n -t configfs -o ${sysfs_opts} configfs /sys/kernel/config
[ -d /sys/fs/fuse/connections ] && mount -n -t fusectl -o ${sysfs_opts} fusectl /sys/fs/fuse/connections
[ -d /sys/fs/selinux ] && mount -n -t selinuxfs -o nosuid,noexec selinuxfs /sys/fs/selinux
[ -d /sys/fs/pstore ] && mount -n -t pstore pstore -o ${sysfs_opts} /sys/fs/pstore
[ -d /sys/firmware/efi/efivars ] && mount -n -t efivarfs -o ro,${sysfs_opts} efivarfs /sys/firmware/efi/efivars
# misc /proc mounted fs
[ -d /proc/sys/fs/binfmt_misc ] && mount -t binfmt_misc -o nodev,noexec,nosuid binfmt_misc /proc/sys/fs/binfmt_misc
# mount cgroups
mount -n -t tmpfs -o nodev,noexec,nosuid,mode=755,size=10m cgroup_root /sys/fs/cgroup
while read name hier groups enabled rest
do
case "${enabled}" in
1) mkdir -p /sys/fs/cgroup/${name}
mount -n -t cgroup -o ${sysfs_opts},${name} ${name} /sys/fs/cgroup/${name}
;;
esac
done < /proc/cgroups
# use hierarchy for memory
echo 1 > /sys/fs/cgroup/memory/memory.use_hierarchy
# for compatibility
mkdir -p /sys/fs/cgroup/systemd
mount -t cgroup -o none,name=systemd cgroup /sys/fs/cgroup/systemd
# start mdev for hotplug
echo "/sbin/mdev" > /proc/sys/kernel/hotplug
# mdev -s will not create /dev/usb[1-9] devices with recent kernels
# so we trigger hotplug events for usb for now
for i in $(find /sys/devices -name 'usb[0-9]*'); do
[ -e $i/uevent ] && echo add > $i/uevent
done
mdev -s
# set hostname
if [ -s /etc/hostname ]
then
hostname -F /etc/hostname
fi
if [ $(hostname) = "(none)" -a -f /sys/class/net/eth0/address ]
then
mac=$(cat /sys/class/net/eth0/address)
hostname linuxkit-$(echo $mac | sed 's/://g')
fi
# set system clock from hwclock
hwclock --hctosys --utc
# bring up loopback interface
ip addr add 127.0.0.1/8 dev lo brd + scope host
ip route add 127.0.0.0/8 dev lo scope host
ip link set lo up
# for containerising dhcpcd and other containers that need writable etc
mkdir /tmp/etc
mv /etc/resolv.conf /tmp/etc/resolv.conf
ln -snf /tmp/etc/resolv.conf /etc/resolv.conf
# remount rootfs as readonly
mount -o remount,ro /
# make /var writeable and shared
mount -o bind /var /var
mount -o remount,rw,nodev,nosuid,noexec,relatime /var /var
mount --make-rshared /var
# make / rshared
mount --make-rshared /

View File

@ -1,15 +0,0 @@
# /etc/inittab
::sysinit:/etc/init.d/rcS
::once:/etc/init.d/containerd
::once:/etc/init.d/containers
# Stuff to do for the 3-finger salute
::ctrlaltdel:/sbin/reboot
# Stuff to do before rebooting
::shutdown:/usr/sbin/killall5 -15
::shutdown:/bin/sleep 5
::shutdown:/usr/sbin/killall5 -9
::shutdown:/bin/echo "Unmounting filesystems"
::shutdown:/bin/umount -a -r

View File

@ -1,12 +0,0 @@
Welcome to LinuxKit
## .
## ## ## ==
## ## ## ## ## ===
/"""""""""""""""""\___/ ===
{ / ===-
\______ O __/
\ \ __/
\____\_______/

View File

@ -1,45 +0,0 @@
#!/bin/sh
setup_console() {
tty=${1%,*}
speed=${1#*,}
inittab="$2"
securetty="$3"
line=
term="linux"
[ "$speed" = "$1" ] && speed=115200
case "$tty" in
ttyS*|ttyAMA*|ttyUSB*|ttyMFD*)
line="-L"
term="vt100"
;;
tty?)
line=""
speed="38400"
term=""
;;
esac
# skip consoles already in inittab
grep -q "^$tty:" "$inittab" && return
echo "$tty::once:cat /etc/issue" >> "$inittab"
echo "$tty::respawn:/sbin/getty -n -l /bin/sh $line $speed $tty $term" >> "$inittab"
if ! grep -q -w "$tty" "$securetty"; then
echo "$tty" >> "$securetty"
fi
}
/bin/mount -t tmpfs tmpfs /mnt
/bin/cp -a / /mnt 2>/dev/null
/bin/mount -t proc -o noexec,nosuid,nodev proc /proc
for opt in $(cat /proc/cmdline); do
case "$opt" in
console=*)
setup_console ${opt#console=} /mnt/etc/inittab /mnt/etc/securetty;;
esac
done
exec /bin/busybox switch_root /mnt /sbin/init

View File

@ -1,5 +0,0 @@
usr
hash
containers
.*
sbin

View File

@ -1,3 +0,0 @@
FROM scratch
COPY . ./
WORKDIR /

View File

@ -1,3 +0,0 @@
FROM scratch
COPY . ./
CMD ["/usr/bin/memlogd","-fd","3"]

View File

@ -1,66 +0,0 @@
GO_COMPILE=mobylinux/go-compile:3afebc59c5cde31024493c3f91e6102d584a30b9@sha256:e0786141ea7df8ba5735b63f2a24b4ade9eae5a02b0e04c4fca33b425ec69b0a
SHA_IMAGE=alpine:3.5@sha256:dfbd4a3a8ebca874ebd2474f044a0b33600d4523d03b0df76e5c5986cb02d7e8
MEMLOGD_BINARY=usr/bin/memlogd
LOGWRITE_BINARY=usr/bin/logwrite
STARTMEMLOGD_BINARY=usr/bin/startmemlogd
LOGREAD_BINARY=sbin/logread
IMAGE=memlogd
.PHONY: tag push clean container
default: tag
DEPS=$(MEMLOGD_BINARY) $(LOGWRITE_BINARY) $(STARTMEMLOGD_BINARY) $(LOGREAD_BINARY)
$(MEMLOGD_BINARY): cmd/memlogd/main.go
mkdir -p $(dir $@)
tar -Ccmd/memlogd -cf - main.go | docker run --rm --net=none --log-driver=none -i $(GO_COMPILE) -o $@ | tar xf -
$(LOGWRITE_BINARY): cmd/logwrite/main.go
mkdir -p $(dir $@)
tar -Ccmd/logwrite -cf - main.go | docker run --rm --net=none --log-driver=none -i $(GO_COMPILE) -o $@ | tar xf -
$(STARTMEMLOGD_BINARY): cmd/startmemlogd/main.go
mkdir -p $(dir $@)
tar -Ccmd/startmemlogd -cf - main.go | docker run --rm --net=none --log-driver=none -i $(GO_COMPILE) -o $@ | tar xf -
$(LOGREAD_BINARY): cmd/logread/main.go
mkdir -p $(dir $@)
tar -Ccmd/logread -cf - main.go | docker run --rm --net=none --log-driver=none -i $(GO_COMPILE) -o $@ | tar xf -
containers: $(MEMLOGD_BINARY) Dockerfile.memlogd config.json
mkdir -p containers/init/memlogd/rootfs
tar -cf - $^ | docker build -f Dockerfile.memlogd -t $(IMAGE):build1 --no-cache -
docker create --name $(IMAGE)-build1 $(IMAGE):build1
docker export $(IMAGE)-build1 | tar -Ccontainers/init/memlogd/rootfs -xv -
docker rm $(IMAGE)-build1
docker rmi $(IMAGE):build1
mv containers/init/memlogd/rootfs/Dockerfile.memlogd containers/init/memlogd/rootfs/Dockerfile
mv containers/init/memlogd/rootfs/config.json containers/init/memlogd
container: Dockerfile $(LOGWRITE_BINARY) $(STARTMEMLOGD_BINARY) $(LOGREAD_BINARY) containers
tar cf - $^ | docker build --no-cache -t $(IMAGE):build -
hash: Dockerfile Dockerfile.memlogd $(DEPS)
find $^ -type f | xargs cat | docker run --rm -i $(SHA_IMAGE) sha1sum - | sed 's/ .*//' > hash
push: hash container
docker pull linuxkit/$(IMAGE):$(shell cat hash) || \
(docker tag $(IMAGE):build linuxkit/$(IMAGE):$(shell cat hash) && \
docker push linuxkit/$(IMAGE):$(shell cat hash))
docker rmi $(IMAGE):build
rm -f hash
tag: hash container
docker pull linuxkit/$(IMAGE):$(shell cat hash) || \
docker tag $(IMAGE):build linuxkit/$(IMAGE):$(shell cat hash)
docker rmi $(IMAGE):build
rm -f hash
clean:
rm -rf hash usr containers sbin
.DELETE_ON_ERROR:

View File

@ -1,115 +0,0 @@
{
"ociVersion": "1.0.0-rc5-dev",
"platform": {
"os": "linux",
"arch": "amd64"
},
"process": {
"consoleSize": {
"height": 0,
"width": 0
},
"user": {
"uid": 0,
"gid": 0
},
"args": [
"/usr/bin/memlogd",
"-fd-log",
"3",
"-fd-query",
"4"
],
"env": [
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
],
"cwd": "/",
"capabilities": {}
},
"root": {
"path": "rootfs",
"readonly": true
},
"mounts": [
{
"destination": "/proc",
"type": "proc",
"source": "proc",
"options": [
"nosuid",
"nodev",
"noexec",
"relatime"
]
},
{
"destination": "/dev",
"type": "tmpfs",
"source": "tmpfs",
"options": [
"nosuid",
"strictatime",
"mode=755",
"size=65536k",
"ro"
]
},
{
"destination": "/sys",
"type": "sysfs",
"source": "sysfs",
"options": [
"nosuid",
"noexec",
"nodev",
"ro"
]
},
{
"destination": "/dev/pts",
"type": "devpts",
"source": "devpts",
"options": [
"nosuid",
"noexec",
"newinstance",
"ptmxmode=0666",
"mode=0620"
]
},
{
"destination": "/sys/fs/cgroup",
"type": "cgroup",
"source": "cgroup",
"options": [
"nosuid",
"noexec",
"nodev",
"relatime",
"ro"
]
}
],
"linux": {
"resources": {
"disableOOMKiller": false
},
"namespaces": [
{
"type": "network"
},
{
"type": "pid"
},
{
"type": "ipc"
},
{
"type": "uts"
},
{
"type": "mount"
}
]
}
}

View File

@ -2,7 +2,7 @@ kernel:
image: "linuxkitprojects/kernel-memorizer:4.10_dbg-17e2eee03ab59f8df8a9c10ace003a84aec2f540"
cmdline: "console=ttyS0"
init:
- linuxkit/init:0e4af96fecc8f752c80d41c0b7d06570cc1dc6b2
- linuxkit/init:6cc1442112980c889230b6449df09d5b48de6854
- linuxkit/runc:v0.4
- linuxkit/containerd:27a4c84cc8fab2d5ea04342546ecd20453ec99b3
onboot:

View File

@ -2,7 +2,7 @@ kernel:
image: linuxkit/kernel:4.9.34
cmdline: "console=ttyS0 page_poison=1"
init:
- linuxkit/init:0e4af96fecc8f752c80d41c0b7d06570cc1dc6b2
- linuxkit/init:6cc1442112980c889230b6449df09d5b48de6854
- linuxkit/runc:v0.4
- linuxkit/containerd:27a4c84cc8fab2d5ea04342546ecd20453ec99b3
- linuxkit/ca-certificates:v0.4

View File

@ -2,7 +2,7 @@ kernel:
image: linuxkit/kernel:4.14.53
cmdline: "console=ttyS0 page_poison=1"
init:
- linuxkit/init:0e4af96fecc8f752c80d41c0b7d06570cc1dc6b2
- linuxkit/init:6cc1442112980c889230b6449df09d5b48de6854
- linuxkit/runc:v0.4
- linuxkit/containerd:27a4c84cc8fab2d5ea04342546ecd20453ec99b3
onboot:

View File

@ -2,7 +2,7 @@ kernel:
image: okernel:latest
cmdline: "console=tty0 page_poison=1"
init:
- linuxkit/init:0e4af96fecc8f752c80d41c0b7d06570cc1dc6b2
- linuxkit/init:6cc1442112980c889230b6449df09d5b48de6854
- linuxkit/runc:v0.4
- linuxkit/containerd:27a4c84cc8fab2d5ea04342546ecd20453ec99b3
- linuxkit/ca-certificates:v0.4

View File

@ -2,7 +2,7 @@ kernel:
image: linuxkitprojects/kernel-shiftfs:4.11.4-881a041fc14bd95814cf140b5e98d97dd65160b5
cmdline: "console=ttyS0 console=tty0 page_poison=1"
init:
- linuxkit/init:0e4af96fecc8f752c80d41c0b7d06570cc1dc6b2
- linuxkit/init:6cc1442112980c889230b6449df09d5b48de6854
- linuxkit/runc:v0.4
- linuxkit/containerd:27a4c84cc8fab2d5ea04342546ecd20453ec99b3
- linuxkit/ca-certificates:v0.4

View File

@ -2,7 +2,7 @@ kernel:
image: linuxkit/kernel:4.14.53
cmdline: "console=ttyS0"
init:
- linuxkit/init:0e4af96fecc8f752c80d41c0b7d06570cc1dc6b2
- linuxkit/init:6cc1442112980c889230b6449df09d5b48de6854
- linuxkit/runc:v0.4
onboot:
- name: dhcpcd

View File

@ -2,7 +2,7 @@ kernel:
image: linuxkit/kernel:4.14.53
cmdline: "console=ttyS0 console=ttyAMA0"
init:
- linuxkit/init:0e4af96fecc8f752c80d41c0b7d06570cc1dc6b2
- linuxkit/init:6cc1442112980c889230b6449df09d5b48de6854
- linuxkit/runc:v0.4
onboot:
- name: poweroff

View File

@ -2,7 +2,7 @@ kernel:
image: linuxkit/kernel:4.14.53
cmdline: "console=ttyS0 console=ttyAMA0"
init:
- linuxkit/init:0e4af96fecc8f752c80d41c0b7d06570cc1dc6b2
- linuxkit/init:6cc1442112980c889230b6449df09d5b48de6854
- linuxkit/runc:v0.4
onboot:
- name: poweroff

View File

@ -2,7 +2,7 @@ kernel:
image: linuxkit/kernel:4.14.53
cmdline: "console=ttyS0"
init:
- linuxkit/init:0e4af96fecc8f752c80d41c0b7d06570cc1dc6b2
- linuxkit/init:6cc1442112980c889230b6449df09d5b48de6854
- linuxkit/runc:v0.4
onboot:
- name: poweroff

View File

@ -2,7 +2,7 @@ kernel:
image: linuxkit/kernel:4.14.53
cmdline: "console=ttyS0"
init:
- linuxkit/init:0e4af96fecc8f752c80d41c0b7d06570cc1dc6b2
- linuxkit/init:6cc1442112980c889230b6449df09d5b48de6854
- linuxkit/runc:v0.4
onboot:
- name: poweroff

View File

@ -2,7 +2,7 @@ kernel:
image: linuxkit/kernel:4.14.53
cmdline: "console=ttyS0"
init:
- linuxkit/init:0e4af96fecc8f752c80d41c0b7d06570cc1dc6b2
- linuxkit/init:6cc1442112980c889230b6449df09d5b48de6854
- linuxkit/runc:v0.4
onboot:
- name: poweroff

View File

@ -2,7 +2,7 @@ kernel:
image: linuxkit/kernel:4.14.53
cmdline: "console=ttyS0"
init:
- linuxkit/init:0e4af96fecc8f752c80d41c0b7d06570cc1dc6b2
- linuxkit/init:6cc1442112980c889230b6449df09d5b48de6854
- linuxkit/runc:v0.4
onboot:
- name: poweroff

View File

@ -2,7 +2,7 @@ kernel:
image: linuxkit/kernel:4.14.53
cmdline: "console=ttyS0"
init:
- linuxkit/init:0e4af96fecc8f752c80d41c0b7d06570cc1dc6b2
- linuxkit/init:6cc1442112980c889230b6449df09d5b48de6854
- linuxkit/runc:v0.4
onboot:
- name: poweroff

View File

@ -2,7 +2,7 @@ kernel:
image: linuxkit/kernel:4.14.53
cmdline: "console=ttyS0"
init:
- linuxkit/init:0e4af96fecc8f752c80d41c0b7d06570cc1dc6b2
- linuxkit/init:6cc1442112980c889230b6449df09d5b48de6854
- linuxkit/runc:v0.4
onboot:
- name: poweroff

View File

@ -2,7 +2,7 @@ kernel:
image: linuxkit/kernel:4.14.53
cmdline: "console=ttyS0"
init:
- linuxkit/init:0e4af96fecc8f752c80d41c0b7d06570cc1dc6b2
- linuxkit/init:6cc1442112980c889230b6449df09d5b48de6854
- linuxkit/runc:v0.4
onboot:
- name: poweroff

View File

@ -2,7 +2,7 @@ kernel:
image: linuxkit/kernel:4.14.53
cmdline: "console=ttyS0"
init:
- linuxkit/init:0e4af96fecc8f752c80d41c0b7d06570cc1dc6b2
- linuxkit/init:6cc1442112980c889230b6449df09d5b48de6854
- linuxkit/runc:v0.4
onboot:
- name: poweroff

View File

@ -2,7 +2,7 @@ kernel:
image: linuxkit/kernel:4.14.53
cmdline: "console=ttyS0"
init:
- linuxkit/init:0e4af96fecc8f752c80d41c0b7d06570cc1dc6b2
- linuxkit/init:6cc1442112980c889230b6449df09d5b48de6854
- linuxkit/runc:v0.4
- linuxkit/containerd:27a4c84cc8fab2d5ea04342546ecd20453ec99b3
services:

View File

@ -2,7 +2,7 @@ kernel:
image: linuxkit/kernel:4.4.139
cmdline: "console=ttyS0 console=ttyAMA0"
init:
- linuxkit/init:0e4af96fecc8f752c80d41c0b7d06570cc1dc6b2
- linuxkit/init:6cc1442112980c889230b6449df09d5b48de6854
- linuxkit/runc:v0.4
onboot:
- name: check-kernel-config

View File

@ -2,7 +2,7 @@ kernel:
image: linuxkit/kernel:4.9.111
cmdline: "console=ttyS0 console=ttyAMA0"
init:
- linuxkit/init:0e4af96fecc8f752c80d41c0b7d06570cc1dc6b2
- linuxkit/init:6cc1442112980c889230b6449df09d5b48de6854
- linuxkit/runc:v0.4
onboot:
- name: check-kernel-config

View File

@ -2,7 +2,7 @@ kernel:
image: linuxkit/kernel:4.14.53
cmdline: "console=ttyS0 console=ttyAMA0"
init:
- linuxkit/init:0e4af96fecc8f752c80d41c0b7d06570cc1dc6b2
- linuxkit/init:6cc1442112980c889230b6449df09d5b48de6854
- linuxkit/runc:v0.4
onboot:
- name: check-kernel-config

View File

@ -2,7 +2,7 @@ kernel:
image: linuxkit/kernel:4.17.4
cmdline: "console=ttyS0 console=ttyAMA0"
init:
- linuxkit/init:0e4af96fecc8f752c80d41c0b7d06570cc1dc6b2
- linuxkit/init:6cc1442112980c889230b6449df09d5b48de6854
- linuxkit/runc:v0.4
onboot:
- name: check-kernel-config

View File

@ -2,7 +2,7 @@ kernel:
image: linuxkit/kernel:4.4.139
cmdline: "console=ttyS0 console=ttyAMA0"
init:
- linuxkit/init:0e4af96fecc8f752c80d41c0b7d06570cc1dc6b2
- linuxkit/init:6cc1442112980c889230b6449df09d5b48de6854
- linuxkit/runc:v0.4
onboot:
- name: check

View File

@ -2,7 +2,7 @@ kernel:
image: linuxkit/kernel:4.9.111
cmdline: "console=ttyS0 console=ttyAMA0"
init:
- linuxkit/init:0e4af96fecc8f752c80d41c0b7d06570cc1dc6b2
- linuxkit/init:6cc1442112980c889230b6449df09d5b48de6854
- linuxkit/runc:v0.4
onboot:
- name: check

View File

@ -2,7 +2,7 @@ kernel:
image: linuxkit/kernel:4.14.53
cmdline: "console=ttyS0 console=ttyAMA0"
init:
- linuxkit/init:0e4af96fecc8f752c80d41c0b7d06570cc1dc6b2
- linuxkit/init:6cc1442112980c889230b6449df09d5b48de6854
- linuxkit/runc:v0.4
onboot:
- name: check

View File

@ -2,7 +2,7 @@ kernel:
image: linuxkit/kernel:4.17.4
cmdline: "console=ttyS0 console=ttyAMA0"
init:
- linuxkit/init:0e4af96fecc8f752c80d41c0b7d06570cc1dc6b2
- linuxkit/init:6cc1442112980c889230b6449df09d5b48de6854
- linuxkit/runc:v0.4
onboot:
- name: check

View File

@ -2,7 +2,7 @@ kernel:
image: linuxkit/kernel:4.14.53
cmdline: "console=ttyS0 console=ttyAMA0"
init:
- linuxkit/init:0e4af96fecc8f752c80d41c0b7d06570cc1dc6b2
- linuxkit/init:6cc1442112980c889230b6449df09d5b48de6854
- linuxkit/runc:v0.4
trust:
org:

View File

@ -2,7 +2,7 @@ kernel:
image: linuxkit/kernel:4.14.53
cmdline: "console=ttyS0"
init:
- linuxkit/init:0e4af96fecc8f752c80d41c0b7d06570cc1dc6b2
- linuxkit/init:6cc1442112980c889230b6449df09d5b48de6854
- linuxkit/runc:v0.4
- linuxkit/containerd:27a4c84cc8fab2d5ea04342546ecd20453ec99b3
- linuxkit/ca-certificates:v0.4

View File

@ -2,7 +2,7 @@ kernel:
image: linuxkit/kernel:4.14.53
cmdline: "console=ttyS0 page_poison=1"
init:
- linuxkit/init:0e4af96fecc8f752c80d41c0b7d06570cc1dc6b2
- linuxkit/init:6cc1442112980c889230b6449df09d5b48de6854
- linuxkit/runc:v0.4
onboot:
- name: test

View File

@ -2,7 +2,7 @@ kernel:
image: linuxkit/kernel:4.14.53
cmdline: "console=ttyS0 console=ttyAMA0"
init:
- linuxkit/init:0e4af96fecc8f752c80d41c0b7d06570cc1dc6b2
- linuxkit/init:6cc1442112980c889230b6449df09d5b48de6854
- linuxkit/runc:v0.4
onboot:
- name: binfmt

View File

@ -2,7 +2,7 @@ kernel:
image: linuxkit/kernel:4.14.53
cmdline: "console=ttyS0 console=ttyAMA0"
init:
- linuxkit/init:0e4af96fecc8f752c80d41c0b7d06570cc1dc6b2
- linuxkit/init:6cc1442112980c889230b6449df09d5b48de6854
- linuxkit/runc:v0.4
- linuxkit/ca-certificates:v0.4
onboot:

View File

@ -2,7 +2,7 @@ kernel:
image: linuxkit/kernel:4.14.53
cmdline: "console=ttyS0 console=ttyAMA0"
init:
- linuxkit/init:0e4af96fecc8f752c80d41c0b7d06570cc1dc6b2
- linuxkit/init:6cc1442112980c889230b6449df09d5b48de6854
- linuxkit/runc:v0.4
- linuxkit/containerd:27a4c84cc8fab2d5ea04342546ecd20453ec99b3
- linuxkit/ca-certificates:v0.4

View File

@ -2,7 +2,7 @@ kernel:
image: linuxkit/kernel:4.14.53
cmdline: "console=ttyS0 console=ttyAMA0"
init:
- linuxkit/init:0e4af96fecc8f752c80d41c0b7d06570cc1dc6b2
- linuxkit/init:6cc1442112980c889230b6449df09d5b48de6854
- linuxkit/runc:v0.4
onboot:
- name: dhcpcd

View File

@ -2,7 +2,7 @@ kernel:
image: linuxkit/kernel:4.14.53
cmdline: "console=ttyS0 console=ttyAMA0"
init:
- linuxkit/init:0e4af96fecc8f752c80d41c0b7d06570cc1dc6b2
- linuxkit/init:6cc1442112980c889230b6449df09d5b48de6854
- linuxkit/runc:v0.4
onboot:
- name: format

View File

@ -2,7 +2,7 @@ kernel:
image: linuxkit/kernel:4.14.53
cmdline: "console=ttyS0 console=ttyAMA0"
init:
- linuxkit/init:0e4af96fecc8f752c80d41c0b7d06570cc1dc6b2
- linuxkit/init:6cc1442112980c889230b6449df09d5b48de6854
- linuxkit/runc:v0.4
onboot:
- name: extend

View File

@ -2,7 +2,7 @@ kernel:
image: linuxkit/kernel:4.14.53
cmdline: "console=ttyS0 console=ttyAMA0"
init:
- linuxkit/init:0e4af96fecc8f752c80d41c0b7d06570cc1dc6b2
- linuxkit/init:6cc1442112980c889230b6449df09d5b48de6854
- linuxkit/runc:v0.4
onboot:
- name: modprobe

View File

@ -2,7 +2,7 @@ kernel:
image: linuxkit/kernel:4.14.53
cmdline: "console=ttyS0 console=ttyAMA0"
init:
- linuxkit/init:0e4af96fecc8f752c80d41c0b7d06570cc1dc6b2
- linuxkit/init:6cc1442112980c889230b6449df09d5b48de6854
- linuxkit/runc:v0.4
onboot:
- name: modprobe

View File

@ -2,7 +2,7 @@ kernel:
image: linuxkit/kernel:4.14.53
cmdline: "console=ttyS0 console=ttyAMA0"
init:
- linuxkit/init:0e4af96fecc8f752c80d41c0b7d06570cc1dc6b2
- linuxkit/init:6cc1442112980c889230b6449df09d5b48de6854
- linuxkit/runc:v0.4
onboot:
- name: format

View File

@ -2,7 +2,7 @@ kernel:
image: linuxkit/kernel:4.14.53
cmdline: "console=ttyS0 console=ttyAMA0"
init:
- linuxkit/init:0e4af96fecc8f752c80d41c0b7d06570cc1dc6b2
- linuxkit/init:6cc1442112980c889230b6449df09d5b48de6854
- linuxkit/runc:v0.4
onboot:
- name: extend

View File

@ -2,7 +2,7 @@ kernel:
image: linuxkit/kernel:4.14.53
cmdline: "console=ttyS0 console=ttyAMA0"
init:
- linuxkit/init:0e4af96fecc8f752c80d41c0b7d06570cc1dc6b2
- linuxkit/init:6cc1442112980c889230b6449df09d5b48de6854
- linuxkit/runc:v0.4
onboot:
- name: format

View File

@ -2,7 +2,7 @@ kernel:
image: linuxkit/kernel:4.14.53
cmdline: "console=ttyS0 console=ttyAMA0"
init:
- linuxkit/init:0e4af96fecc8f752c80d41c0b7d06570cc1dc6b2
- linuxkit/init:6cc1442112980c889230b6449df09d5b48de6854
- linuxkit/runc:v0.4
onboot:
- name: format

Some files were not shown because too many files have changed in this diff Show More