1 of 49

Processes and Services

2 of 49

Who am I?

Infrastructure Engineer @ Yelp

Formerly Berkeley / OCF

Chris Kuehl

ckuehl@ocf.berkeley.edu

3 of 49

What is this lecture about?

Chapter 1: Processes

Chapter 2: Init systems & services

4 of 49

CHAPTER ONE

Processes

5 of 49

What is a process?

It’s just ~one running program.

Each process has its own memory space, threads, code, etc.

6 of 49

Process hierarchy

Each process has one parent, typically the process that started it.

Processes can have many children.

7 of 49

Processes vs threads

Both methods of running code “at the same time”

A process is a collection of one or more threads

Threads are all part of the same “program”, share the same memory

Processes communicate over some interface

8 of 49

So why is my laptop running 6000 chrome processes?

9 of 49

How are processes created?

A process “forks” into two separate processes using the fork syscall

The parent keeps its PID, the child gets a new PID.

10 of 49

How many “hello”s get printed?

int main(void) {� fork();� printf("hello: %d\n", getpid());�}

11 of 49

How many “hello”s get printed?

int main(void) {� fork();� printf("hello: %d\n", getpid());�}

int main(void) {� fork();� printf("hello: %d\n", getpid());�}

int main(void) {� fork();� printf("hello: %d\n", getpid());�}

Process ID 1000

Process ID 1000

Process ID 2000

12 of 49

How many “hello”s get printed?

int main(void) {� fork();� printf("hello: %d\n", getpid());�}

int main(void) {� fork();� printf("hello: %d\n", getpid());�}

int main(void) {� fork();� printf("hello: %d\n", getpid());�}

$ ./foo

hello: 27951

hello: 27952

Process ID 1000

Process ID 1000

Process ID 2000

13 of 49

How many “hello”s get printed?

int main(void) {� fork();

fork();

fork();� printf("hello: %d\n", getpid());�}

14 of 49

How many “hello”s get printed?

int main(void) {� fork();

fork();

fork();� printf("hello: %d\n", getpid());�}

$ ./foo

hello: 27956

hello: 27958

hello: 27959

hello: 27957

hello: 27961

hello: 27960

hello: 27963

hello: 27962

15 of 49

How to make the child do something else?

pid_t result = fork();�if (result > 0) {� /* parent process */� sleep(100);

} else if (result == 0) {� /* child process */� sleep(10);

} else { /* error */ }

Process tree after start:

child exits first

16 of 49

What happens when processes exit?

pid_t result = fork();�if (result > 0) {� /* parent process */� sleep(100);

} else if (result == 0) {� /* child process */� sleep(10);

} else { /* error */ }

Process tree after start:

After 10 seconds:

????

17 of 49

When a process exits, it temporarily becomes a zombie:

  • No longer running�
  • Still exists in process table so parent can collect exit status, uses no other resources�
  • Totally normal!

Zombie processes

18 of 49

19 of 49

What happens when a process dies?

pid_t result = fork();�if (result > 0) {� /* parent process */� sleep(100);

} else if (result == 0) {� /* child process */� exit(123);

} else { /* error */ }

Processes always exit with an “exit code” (int between 0 and 255)

Typically, 0 is success, anything else is an error

20 of 49

Parents need to wait() on children

pid_t result = fork();�if (result > 0) {� /* parent process */int status;� wait(&status);� printf("%d\n", WEXITSTATUS(status));�} else if (result == 0) {� /* child process */� sleep(10);

exit(123);�} else { /* error */ }

Process tree after start:

After 10 seconds:

Prints out:

(aka reap)

21 of 49

What if the parent exits first?

pid_t result = fork();�if (result > 0) {� /* parent process */

sleep(1);� exit(0);�} else if (result == 0) {� /* child process */� sleep(10);

exit(123);�} else { /* error */ }

Process tree after start:

After 1 second:

Orphaned processes are re-parented under PID 1

parent

child

child

22 of 49

Process signaling

Simple messages to other processes.

  • SIGTERM: “please exit”
  • SIGINT: interrupt, generated by ^C in the terminal
  • SIGKILL: kill immediately without a chance to clean up
  • SIGWINCH: terminal was resized
  • SIGHUP: terminal was closed
  • SIGSTOP / SIGCONT: pause/resume

Typically send using kill or pkill, e.g. kill -9 <pid> or pkill -HUP apache2.

23 of 49

How do processes communicate?

All kinds of inter-process communication (IPC):

  • Exiting with a status code
  • Signals (e.g. SIGTERM, SIGKILL, SIGHUP)
  • Pipes (just like stdin, stdout, stderr)
  • Network (e.g. TCP or UNIX sockets)
  • Message bus (e.g. dbus)
  • ...and tons more...

24 of 49

Working with processes: ps

Nobody remembers what the arguments to ps mean, just memorize a few you find useful :)

ps aux

ps xawuf

ps -o pid,uname,comm

25 of 49

Working with processes: pstree

26 of 49

Working with processes: pgrep & pkill

(pgrep is especially useful for composing)

27 of 49

Working with processes: htop

(makes pretty screenshots)

28 of 49

CHAPTER TWO

Init systems & services

29 of 49

What is an init system?

The first process launched (PID 1), lives forever

Core responsibilities:

  • Launching enough processes to make the system useful
  • Reap orphaned zombie processes

30 of 49

What does a bare-bones init system look like?

/bin/bash can work in a pinch�

What about in code?

31 of 49

Bare-bones init

pid_t result = fork();� if (result > 0) {

/* parent process */while (wait(NULL) != result) {}� } else if (result == 0) {� /* child process */� execl("/bin/bash", "bash"); // any process here� } else { /* error */ }

reaps all children, even those it didn’t spawn (orphans)

spawns some useful process

32 of 49

Traditional init systems

Even traditional init systems do more than the minimum required.

Typical extra responsibilities:

  • coordinating startup/shutdown (often via “runlevels”)
  • launching services
  • handling signals

33 of 49

Different kinds of processes

Not strict definitions:

  • Interactive: foreground processes like chrome, vim, htop�
  • Daemons: background processes like sshd, httpd, rsyslogd, nginx, postfix

34 of 49

How do we control services?

Lots of ways…

  • We could signal processes (e.g. kill -HUP)
  • We could use their CLIs (rndc, apachectl, etc.)
  • We could rely on our init systems

Let’s look at how init systems do it...

35 of 49

“Old”-style init scripts

Turing-complete, actual scripts:�/etc/init.d/$service $action

Each script is responsible for keeping track of processes.

  • Typically PID files (can be stale, race-prone)
  • Inconsistent actions provided (start/stop/restart, reload, graceful, status, etc.)
  • Inconsistent behavior and output (e.g. status command)
  • Incredibly annoying to write, often copy-pasted

36 of 49

“Old”-style init scripts

/etc/init.d/nginx on ubuntu

37 of 49

What would modern service supervision look like?

Let’s look at some examples...

Traditional

Modern

Scripts that can do anything

Declarative config files

Store state using PID files

Store state in the init system

Inconsistent actions (each init script its own CLI)

Consistent actions via common CLI

Difficult to control ordering

Ordering via dependencies or events

38 of 49

Modern init system: upstart

Developed by Canonical (Ubuntu), used for a few releases

Event-based (services subscribe to events)

Parallel start and stop

Way easier to write than�traditional init scripts

39 of 49

Modern init system: upstart

description "my cool server"��start on filesystem and started networking�stop on shutdown��exec /usr/bin/my-cool-server

/etc/init/my-cool-server.conf

40 of 49

Modern init system: systemd

Originally comes from Fedora-land

Dependency-based

Parallel start and stop

Way easier to write than traditional init scripts

41 of 49

Modern init system: systemd

Goals:

  • Unify core Linux tooling across distributions
  • Provide excellent UX

Ended up reimplementing syslog, cron, networking, GRUB, ConsoleKit, udev

42 of 49

Turns out they’re controversial

43 of 49

In practice, systemd has won

...

44 of 49

systemctl status

systemctl start/stop

systemctl enable/disable

45 of 49

systemctl (no arguments)

46 of 49

journalctl

View recent logs from a unit:�journalctl -u $unit -e

Tail logs from a unit:�journalctl -u $unit -f

47 of 49

Writing systemd unit files

[Unit]

Description=my cool server

Requires=network-online.target opt.mount

After=network-online.target opt.mount

[Service]

ExecStart=/usr/bin/my-cool-service

[Install]

WantedBy=multi-user.target

/etc/systemd/system/my-cool-server.service

48 of 49

Conclusion (i.e. opinions)

  • Think about the UNIX philosophy as a guiding principle, not a law�
  • Focus on the health of entire systems�
  • How can you be most productive & design things reliably?

49 of 49

Signin

decal.ocf.berkeley.edu/signin

Week 6: Engelbart