mirror of
https://github.com/opencontainers/runc.git
synced 2026-07-11 06:03:57 +08:00
@@ -19,10 +19,10 @@ process are specified in this file. The configuration is used for each process
|
||||
|
||||
See the `sample_configs` folder for examples of what the container configuration should look like.
|
||||
|
||||
Using this configuration and the current directory holding the rootfs for a process, one can use libcontainer to exec the container. Running the life of the namespace, a `pid` file
|
||||
is written to the current directory with the pid of the namespaced process to the external world. A client can use this pid to wait, kill, or perform other operation with the container. If a user tries to run a new process inside an existing container with a live namespace, the namespace will be joined by the new process.
|
||||
Using this configuration and the current directory holding the rootfs for a process, one can use libcontainer to exec the container. During the life of the container, a `state.json` file
|
||||
is written to the current directory with the pid and start time of the container's PID1. A client can use this pid to wait, kill, or perform other operation with the container. If a user tries to run a new process inside an existing container with a live namespace, the namespace will be joined by the new process.
|
||||
|
||||
You may also specify an alternate root place where the `container.json` file is read and where the `pid` file will be saved.
|
||||
You may also specify an alternate root place where the `container.json` file is read and where the `state.json` file will be saved.
|
||||
|
||||
#### nsinit
|
||||
|
||||
@@ -38,7 +38,6 @@ nsinit exec /bin/bash
|
||||
If you wish to spawn another process inside the container while your current bash session is
|
||||
running just run the exact same command again to get another bash shell or change the command. If the original process dies, PID 1, all other processes spawned inside the container will also be killed and the namespace will be removed.
|
||||
|
||||
You can identify if a process is running in a container by looking to see if `pid` is in the root of the directory.
|
||||
#### Future
|
||||
See the [roadmap](ROADMAP.md).
|
||||
|
||||
|
||||
+8
-2
@@ -56,12 +56,18 @@ func Exec(container *libcontainer.Config, term Terminal, rootfs, dataPath string
|
||||
if err != nil {
|
||||
return -1, err
|
||||
}
|
||||
if err := WritePid(dataPath, command.Process.Pid, started); err != nil {
|
||||
|
||||
state := &libcontainer.State{
|
||||
InitPid: command.Process.Pid,
|
||||
InitStartTime: started,
|
||||
}
|
||||
|
||||
if err := libcontainer.SaveState(dataPath, state); err != nil {
|
||||
command.Process.Kill()
|
||||
command.Wait()
|
||||
return -1, err
|
||||
}
|
||||
defer DeletePid(dataPath)
|
||||
defer libcontainer.DeleteState(dataPath)
|
||||
|
||||
// Do this before syncing with child so that no children
|
||||
// can escape the cgroup
|
||||
|
||||
@@ -13,7 +13,7 @@ import (
|
||||
)
|
||||
|
||||
// ExecIn uses an existing pid and joins the pid's namespaces with the new command.
|
||||
func ExecIn(container *libcontainer.Config, nspid int, args []string) error {
|
||||
func ExecIn(container *libcontainer.Config, state *libcontainer.State, args []string) error {
|
||||
// TODO(vmarmol): If this gets too long, send it over a pipe to the child.
|
||||
// Marshall the container into JSON since it won't be available in the namespace.
|
||||
containerJson, err := json.Marshal(container)
|
||||
@@ -22,7 +22,7 @@ func ExecIn(container *libcontainer.Config, nspid int, args []string) error {
|
||||
}
|
||||
|
||||
// Enter the namespace and then finish setup
|
||||
finalArgs := []string{os.Args[0], "nsenter", "--nspid", strconv.Itoa(nspid), "--containerjson", string(containerJson), "--"}
|
||||
finalArgs := []string{os.Args[0], "nsenter", "--nspid", strconv.Itoa(state.InitPid), "--containerjson", string(containerJson), "--"}
|
||||
finalArgs = append(finalArgs, args...)
|
||||
if err := system.Execv(finalArgs[0], finalArgs[0:], os.Environ()); err != nil {
|
||||
return err
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
package namespaces
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
// WritePid writes the namespaced processes pid to pid and it's start time
|
||||
// to the path specified
|
||||
func WritePid(path string, pid int, startTime string) error {
|
||||
err := ioutil.WriteFile(filepath.Join(path, "pid"), []byte(fmt.Sprint(pid)), 0655)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return ioutil.WriteFile(filepath.Join(path, "start"), []byte(startTime), 0655)
|
||||
}
|
||||
|
||||
// DeletePid removes the pid and started file from disk when the container's process
|
||||
// dies and the container is cleanly removed
|
||||
func DeletePid(path string) error {
|
||||
err := os.Remove(filepath.Join(path, "pid"))
|
||||
if serr := os.Remove(filepath.Join(path, "start")); err == nil {
|
||||
err = serr
|
||||
}
|
||||
return err
|
||||
}
|
||||
+6
-5
@@ -19,19 +19,20 @@ var execCommand = cli.Command{
|
||||
}
|
||||
|
||||
func execAction(context *cli.Context) {
|
||||
var nspid, exitCode int
|
||||
var exitCode int
|
||||
|
||||
container, err := loadContainer()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
if nspid, err = readPid(); err != nil && !os.IsNotExist(err) {
|
||||
log.Fatalf("unable to read pid: %s", err)
|
||||
state, err := libcontainer.GetState(dataPath)
|
||||
if err != nil && !os.IsNotExist(err) {
|
||||
log.Fatalf("unable to read state.json: %s", err)
|
||||
}
|
||||
|
||||
if nspid > 0 {
|
||||
err = namespaces.ExecIn(container, nspid, []string(context.Args()))
|
||||
if state != nil {
|
||||
err = namespaces.ExecIn(container, state, []string(context.Args()))
|
||||
} else {
|
||||
term := namespaces.NewTerminal(os.Stdin, os.Stdout, os.Stderr, container.Tty)
|
||||
exitCode, err = startContainer(container, term, dataPath, []string(context.Args()))
|
||||
|
||||
@@ -2,11 +2,9 @@ package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
|
||||
"github.com/docker/libcontainer"
|
||||
)
|
||||
@@ -26,20 +24,6 @@ func loadContainer() (*libcontainer.Config, error) {
|
||||
return container, nil
|
||||
}
|
||||
|
||||
func readPid() (int, error) {
|
||||
data, err := ioutil.ReadFile(filepath.Join(dataPath, "pid"))
|
||||
if err != nil {
|
||||
return -1, err
|
||||
}
|
||||
|
||||
pid, err := strconv.Atoi(string(data))
|
||||
if err != nil {
|
||||
return -1, err
|
||||
}
|
||||
|
||||
return pid, nil
|
||||
}
|
||||
|
||||
func openLog(name string) error {
|
||||
f, err := os.OpenFile(name, os.O_CREATE|os.O_RDWR|os.O_APPEND, 0755)
|
||||
if err != nil {
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
package libcontainer
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"os"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
// State represents a running container's state
|
||||
type State struct {
|
||||
// InitPid is the init process id in the parent namespace
|
||||
InitPid int `json:"init_pid,omitempty"`
|
||||
// InitStartTime is the init process start time
|
||||
InitStartTime string `json:"init_start_time,omitempty"`
|
||||
}
|
||||
|
||||
// SaveState writes the container's runtime state to a state.json file
|
||||
// in the specified path
|
||||
func SaveState(basePath string, state *State) error {
|
||||
f, err := os.Create(filepath.Join(basePath, "state.json"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
return json.NewEncoder(f).Encode(state)
|
||||
}
|
||||
|
||||
// GetState reads the state.json file for a running container
|
||||
func GetState(basePath string) (*State, error) {
|
||||
f, err := os.Open(filepath.Join(basePath, "state.json"))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
var state *State
|
||||
if err := json.NewDecoder(f).Decode(&state); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return state, nil
|
||||
}
|
||||
|
||||
// DeleteState deletes the state.json file
|
||||
func DeleteState(basePath string) error {
|
||||
return os.Remove(filepath.Join(basePath, "state.json"))
|
||||
}
|
||||
Reference in New Issue
Block a user