Compare commits
No commits in common. "b2668287aeb7c2582908a5c16c830824fd78efa2" and "a87c5683354a94e6d049e6d40f18a7678f133490" have entirely different histories.
b2668287ae
...
a87c568335
17
Makefile
17
Makefile
@ -1,13 +1,6 @@
|
|||||||
DESTDIR = /usr/local/bin
|
DESTDIR = /usr/local/bin
|
||||||
|
|
||||||
installs = install-dir
|
all: wingmate dummy oneshot spawner starter pidproxy exec
|
||||||
programs = wingmate pidproxy exec
|
|
||||||
ifdef TEST_BUILD
|
|
||||||
programs += oneshot spawner starter dummy
|
|
||||||
installs += install-test
|
|
||||||
endif
|
|
||||||
|
|
||||||
all: ${programs}
|
|
||||||
|
|
||||||
wingmate:
|
wingmate:
|
||||||
$(MAKE) -C cmd/wingmate all
|
$(MAKE) -C cmd/wingmate all
|
||||||
@ -39,16 +32,12 @@ clean:
|
|||||||
$(MAKE) -C cmd/experiment/spawner clean
|
$(MAKE) -C cmd/experiment/spawner clean
|
||||||
$(MAKE) -C cmd/experiment/starter clean
|
$(MAKE) -C cmd/experiment/starter clean
|
||||||
|
|
||||||
install: ${installs}
|
install:
|
||||||
|
install -d ${DESTDIR}
|
||||||
$(MAKE) -C cmd/wingmate DESTDIR=${DESTDIR} install
|
$(MAKE) -C cmd/wingmate DESTDIR=${DESTDIR} install
|
||||||
$(MAKE) -C cmd/pidproxy DESTDIR=${DESTDIR} install
|
$(MAKE) -C cmd/pidproxy DESTDIR=${DESTDIR} install
|
||||||
$(MAKE) -C cmd/exec DESTDIR=${DESTDIR} install
|
$(MAKE) -C cmd/exec DESTDIR=${DESTDIR} install
|
||||||
|
|
||||||
install-test:
|
|
||||||
$(MAKE) -C cmd/experiment/dummy DESTDIR=${DESTDIR} install
|
$(MAKE) -C cmd/experiment/dummy DESTDIR=${DESTDIR} install
|
||||||
$(MAKE) -C cmd/experiment/oneshot DESTDIR=${DESTDIR} install
|
$(MAKE) -C cmd/experiment/oneshot DESTDIR=${DESTDIR} install
|
||||||
$(MAKE) -C cmd/experiment/spawner DESTDIR=${DESTDIR} install
|
$(MAKE) -C cmd/experiment/spawner DESTDIR=${DESTDIR} install
|
||||||
$(MAKE) -C cmd/experiment/starter DESTDIR=${DESTDIR} install
|
$(MAKE) -C cmd/experiment/starter DESTDIR=${DESTDIR} install
|
||||||
|
|
||||||
install-dir:
|
|
||||||
install -d ${DESTDIR}
|
|
||||||
|
|||||||
137
README.md
137
README.md
@ -1,139 +1,2 @@
|
|||||||
# wingmate
|
# wingmate
|
||||||
|
|
||||||
Wingmate is a process manager for services. It works like init. It starts and restarts services.
|
|
||||||
It also has cron feature. It is designed to run in a container/docker.
|
|
||||||
The Wingmate binary do not need any external dependency.
|
|
||||||
Just copy the binary, and exec from the entry point script.
|
|
||||||
|
|
||||||
# Getting Started
|
|
||||||
|
|
||||||
## Binaries
|
|
||||||
|
|
||||||
There are three binaries in this project: `wingmate`, `wmpidproxy`, and `wmexec`.
|
|
||||||
|
|
||||||
`wingmate` is the core binary. It reads config, starts, restarts services. It also
|
|
||||||
runs cron. Read the [configuration](#configuration) section for files needed to run
|
|
||||||
`wingmate`.
|
|
||||||
|
|
||||||
`wmpidproxy` is a helper binary for monitoring _legacy style_ service (fork, exit
|
|
||||||
initial proces, and continue in background). Read [here](#wingmate-pid-proxy-binary)
|
|
||||||
for further details about `wmpidproxy`.
|
|
||||||
|
|
||||||
`wmexec` is a helper binary for running process in different `user` or `group`.
|
|
||||||
It also useful for setting the process as process group leader.
|
|
||||||
Read [here](#wingmate-exec-binary) for further details about `wmexec`.
|
|
||||||
|
|
||||||
## Building a container image based on wingmate image in Docker Hub
|
|
||||||
|
|
||||||
Wingmate has no dependency other than `alpine` base image, so you just need to copy
|
|
||||||
the binaries directly. If you have built your application into an `alpine` based image,
|
|
||||||
all you need to do is copy whichever binary you need, crontab file (if you use cron)
|
|
||||||
and add some shell script to glue them together. Here is a Dockerfile example.
|
|
||||||
|
|
||||||
```Dockerfile
|
|
||||||
# Dockerfile
|
|
||||||
FROM suyono/wingmate:alpine as source
|
|
||||||
|
|
||||||
FROM alpine:latest
|
|
||||||
ADD --chmod=755 wingmate/ /etc/wingmate/
|
|
||||||
ADD --chmod=755 entry.sh /usr/local/bin/entry.sh
|
|
||||||
COPY --from=source /usr/local/bin/wingmate /usr/local/bin/wingmate
|
|
||||||
COPY --from=source /usr/local/bin/wmpidproxy /usr/local/bin/wmpidproxy
|
|
||||||
COPY --from=source /usr/local/bin/wmexec /usr/local/bin/wmexec
|
|
||||||
ENTRYPOINT [ "/usr/local/bin/entry.sh" ]
|
|
||||||
CMD [ "/usr/local/bin/wingmate" ]
|
|
||||||
```
|
|
||||||
You can find some examples for shell script in [alpine docker](docker/alpine) and
|
|
||||||
[bookworm docker](docker/bookworm).
|
|
||||||
|
|
||||||
## Configuration
|
|
||||||
|
|
||||||
When `wingmate` binary starts, it will look for some files. By default, it will
|
|
||||||
try to read the content of `/etc/wingmate` directory. You can change the directory
|
|
||||||
where it reads by setting `WINGMATE_CONFIG_PATH` environment variable. The structure
|
|
||||||
inside the config path should look like this.
|
|
||||||
|
|
||||||
```shell
|
|
||||||
/etc
|
|
||||||
└── wingmate
|
|
||||||
├── crontab
|
|
||||||
├── crontab.d
|
|
||||||
│ ├── cron1.sh
|
|
||||||
│ ├── cron2.sh
|
|
||||||
│ └── cron3.sh
|
|
||||||
└── service
|
|
||||||
├── one.sh
|
|
||||||
└── spawner.sh
|
|
||||||
```
|
|
||||||
|
|
||||||
First, `wingmate` will try to read the content of `service` directory. The content of
|
|
||||||
this directory should be executables (either shell scripts or binaries). The wingmate
|
|
||||||
will run every executable in `service` directory without going into any subdirectory.
|
|
||||||
|
|
||||||
Next, `wingmate` will read the `crontab` file. `wingmate` expects the `crontab` file using
|
|
||||||
common UNIX crontab file format. Something like this
|
|
||||||
|
|
||||||
```shell
|
|
||||||
┌───────────── minute (0–59)
|
|
||||||
│ ┌───────────── hour (0–23)
|
|
||||||
│ │ ┌───────────── day of the month (1–31)
|
|
||||||
│ │ │ ┌───────────── month (1–12)
|
|
||||||
│ │ │ │ ┌───────────── day of the week (0–6) (Sunday to Saturday)
|
|
||||||
│ │ │ │ │
|
|
||||||
│ │ │ │ │
|
|
||||||
│ │ │ │ │
|
|
||||||
* * * * * <commad or shell script or binary>
|
|
||||||
```
|
|
||||||
|
|
||||||
The command part only support simple command and arguments. Shell expression is not supported
|
|
||||||
yet. It is recommended to write a shell script and put the path to shell script in
|
|
||||||
the command part.
|
|
||||||
|
|
||||||
# Appendix
|
|
||||||
## Wingmate PID Proxy binary
|
|
||||||
|
|
||||||
`wingmate` works by monitoring its direct children process. When it sees one of its children
|
|
||||||
exited, it will start the child process again.
|
|
||||||
|
|
||||||
Sometimes you find some services work by running in the background. It means it forks a new
|
|
||||||
process, disconnect the new child from terminal, exit the parent process, and continue
|
|
||||||
running in the child process. This kind of service usually write its background process
|
|
||||||
PID in a pid file.
|
|
||||||
|
|
||||||
To monitor the background services, `wingmate` utilizes `wmpidproxy`. `wmpidproxy` runs
|
|
||||||
in foreground in-place of the background service. It also periodically check whether the
|
|
||||||
background service is still running, in current implementation it checks every second.
|
|
||||||
|
|
||||||
```shell
|
|
||||||
wmpidproxy --pid-file <path to pid file> -- <background service binary/start script>
|
|
||||||
```
|
|
||||||
#### Example
|
|
||||||
Running sshd background with `wingmate` and `wmpidproxy`: [here](example/ssh-docker)
|
|
||||||
|
|
||||||
#### Note
|
|
||||||
|
|
||||||
It is recommended to configure services to run in foreground if they support it. When services
|
|
||||||
running in foreground, they are running as direct children process of `wingmate`.
|
|
||||||
`wingmate` monitors children process effectively. Whenever a child process exited/terminated,
|
|
||||||
`wingmate` will start it again quickly. Running in foreground also removes the overhead of running
|
|
||||||
`wmpidproxy` together with the service.
|
|
||||||
|
|
||||||
## Wingmate Exec binary
|
|
||||||
|
|
||||||
`wingmate` runs all the services as its children using the same `uid`, `gid`, and in the
|
|
||||||
same process group. You can use `wmexec` to run service in different `uid`, `gid`, or make
|
|
||||||
the service process as its own process group leader.
|
|
||||||
|
|
||||||
#### Syntax
|
|
||||||
|
|
||||||
```shell
|
|
||||||
wmexec [--user <uid>[:<gid>]] [--setsid] -- <target executable>
|
|
||||||
```
|
|
||||||
| Option | Parameter | Description |
|
|
||||||
|----------|-----------|----------------------------------------------------------------------------------------------------------|
|
|
||||||
| --user | uid[:gid] | Set the real user ID and the real group id. Uid and Gid can be either in numeric form or in name form |
|
|
||||||
| --setsid | | Set the process become the leader of its own process group, effectively detaching from parent's terminal |
|
|
||||||
|
|
||||||
#### Example
|
|
||||||
|
|
||||||
You can find example for `wmexec` in [here](docker/alpine/etc/wingmate) and [here](docker/bookworm/etc/wingmate)
|
|
||||||
@ -1,8 +1,6 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
|
||||||
"errors"
|
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
@ -94,13 +92,13 @@ func pidProxy(cmd *cobra.Command, args []string) error {
|
|||||||
err error
|
err error
|
||||||
pid int
|
pid int
|
||||||
sc chan os.Signal
|
sc chan os.Signal
|
||||||
t *time.Ticker
|
t *time.Timer
|
||||||
)
|
)
|
||||||
|
|
||||||
sc = make(chan os.Signal, 1)
|
sc = make(chan os.Signal, 1)
|
||||||
signal.Notify(sc, unix.SIGTERM)
|
signal.Notify(sc, unix.SIGTERM)
|
||||||
|
|
||||||
t = time.NewTicker(time.Second)
|
t = time.NewTimer(time.Second)
|
||||||
|
|
||||||
check:
|
check:
|
||||||
for {
|
for {
|
||||||
@ -132,6 +130,8 @@ func readPid(pidFile string) (int, error) {
|
|||||||
var (
|
var (
|
||||||
file *os.File
|
file *os.File
|
||||||
err error
|
err error
|
||||||
|
buf []byte
|
||||||
|
n int
|
||||||
pid64 int64
|
pid64 int64
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -142,15 +142,18 @@ func readPid(pidFile string) (int, error) {
|
|||||||
_ = file.Close()
|
_ = file.Close()
|
||||||
}()
|
}()
|
||||||
|
|
||||||
scanner := bufio.NewScanner(file)
|
buf = make([]byte, 1024)
|
||||||
if scanner.Scan() {
|
n, err = file.Read(buf)
|
||||||
if pid64, err = strconv.ParseInt(scanner.Text(), 10, 64); err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
|
||||||
return int(pid64), nil
|
|
||||||
} else {
|
|
||||||
return 0, errors.New("invalid scanner")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pid64, err = strconv.ParseInt(string(buf[:n]), 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return int(pid64), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func startProcess(arg0 string, args ...string) {
|
func startProcess(arg0 string, args ...string) {
|
||||||
|
|||||||
@ -2,7 +2,6 @@ FROM golang:1.21-alpine as builder
|
|||||||
|
|
||||||
ADD . /root/wingmate
|
ADD . /root/wingmate
|
||||||
WORKDIR /root/wingmate/
|
WORKDIR /root/wingmate/
|
||||||
ARG TEST_BUILD
|
|
||||||
RUN apk add make build-base && CGO_ENABLED=1 make all && make DESTDIR=/usr/local/bin/wingmate install
|
RUN apk add make build-base && CGO_ENABLED=1 make all && make DESTDIR=/usr/local/bin/wingmate install
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -2,7 +2,6 @@ FROM golang:1.21-bookworm as builder
|
|||||||
|
|
||||||
ADD . /root/wingmate
|
ADD . /root/wingmate
|
||||||
WORKDIR /root/wingmate/
|
WORKDIR /root/wingmate/
|
||||||
ARG TEST_BUILD
|
|
||||||
RUN make all && make DESTDIR=/usr/local/bin/wingmate install
|
RUN make all && make DESTDIR=/usr/local/bin/wingmate install
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -1,14 +0,0 @@
|
|||||||
FROM suyono/wingmate:alpine as source
|
|
||||||
|
|
||||||
FROM alpine:3.19
|
|
||||||
|
|
||||||
RUN apk update && apk add tzdata openssh-server && \
|
|
||||||
ln -s /usr/share/zoneinfo/Australia/Sydney /etc/localtime && ssh-keygen -A
|
|
||||||
|
|
||||||
COPY --from=source /usr/local/bin/wingmate /usr/local/bin/
|
|
||||||
COPY --from=source /usr/local/bin/wmpidproxy /usr/local/bin/
|
|
||||||
ADD --chmod=755 example/ssh-docker/entry.sh /usr/local/bin/entry.sh
|
|
||||||
ADD --chmod=755 example/ssh-docker/etc /etc
|
|
||||||
|
|
||||||
ENTRYPOINT [ "/usr/local/bin/entry.sh" ]
|
|
||||||
CMD [ "/usr/local/bin/wingmate" ]
|
|
||||||
@ -1,7 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
|
|
||||||
if [ $# -gt 0 ]; then
|
|
||||||
exec "$@"
|
|
||||||
else
|
|
||||||
exec /usr/local/bin/wingmate
|
|
||||||
fi
|
|
||||||
@ -1,3 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
|
|
||||||
exec /usr/local/bin/wmpidproxy --pid-file /var/run/sshd.pid -- /usr/sbin/sshd
|
|
||||||
Loading…
x
Reference in New Issue
Block a user