Beach, Forest, Mushrooms and Little Bugs

Yesterday I rented a car and took it down towards Santa Cruz, to Henry Cowell State Park. I wanted to see some redwoods and look for mushrooms. Some of the highlights were:

  • Looking at some mycelium underneath a microscope and seeing actual life happening in real-time. I saw little worms and bugs moving around. I saw the threads that make up the mycelium network.
  • Realizing that we, as humans, are a host for so many microorganisms. There are little bugs, so to speak, crawling on us and inside us right now.
  • Hearing the flowing creek and I lay face-up on a fallen tree that created a bridge across the water.
  • Making a quick stop at the beach where I played with my guitar and buried my feet in the sand.

Log Rotation in a Nutshell

The basic idea of log rotation is explained in the following five steps.

  1. You have a program that sends its logs to /var/log/foo.log.
  2. It’s starting to grow to an uncomfortable size.
  3. When it gets too big you rotate it by renaming the file something like /var/log/foo.log.1.
  4. You create a new file called /var/log/foo.log (where your program sends its log to).
  5. You can decide what you want to do with /var/log/foo.log.1. Maybe you compress it or copy it to another server and then delete it.

Many modern Linux distributions the logrotate utility to manage log rotation. By default, it is configured to run daily using cron.

$ cat /etc/logrotate.conf
# see "man logrotate" for details

include /etc/logrotate.d

man logrotate has detailed explanations of the configuration options. It’s suggested that you make a config file in /etc/logrotate.d for each log you want to be managed. Here is an example.

/var/log/myapp {
    monthly
    rotate 24
    create
    compress
}

This configuration will watch /var/log/myapp, rotate the log once a month, compress the rotated log, and create a new empty log after rotation.

That’s pretty much all there is to it.

docker run -it: TTYs and Stdin

I was working on a project that involved running a docker command as a systemd service. The docker command looked something like the following.

docker run -it \
  foobar python3 -c 'import this; print(this)'

When I tried to start the systemd service I saw the following error.

Jan 27 18:37:37 host program[123]: the input device is not a TTY

After some research, I found other people who had the same problem. Their solution was to remove the -t option from the docker command. I tried it, and it worked. I submitted a pull request and my teammate asked what the difference between the two options was. I was a little embarrassed that I couldn’t explain it to him.

The documentation says

-i, –interactive Keep STDIN open even if not attached

docker run –help

and,

-t, –tty Allocate a pseudo-TTY

docker run –help

I learn best by doing. So I created a simple Dockerfile to test out these different options.

FROM python:3-slim
CMD python

Then I built the image.

docker build -t dummy .

I ran the container in four different ways.

$ docker run dummy
$ docker run -i dummy
# .....waits for me to type something
print('hello')
# pressed Ctrl-D to signal End of Transmission
hello
$ docker run -t dummy
Python 3.8.1 (default, Jan  3 2020, 22:55:55)
[GCC 8.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> ^C^Fexit
^D
^C
# ... help! I cannot escape
# because a psuedo-terminal has not been allocated
$ docker run -it dummy
Python 3.8.1 (default, Jan  3 2020, 22:55:55)
[GCC 8.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>>
KeyboardInterrupt
>>>
# I pressed Ctrl-C to kill the process

Summary

-i by itself tells docker to connect the terminal stdin to the container’s stdin.

$ docker run -i alpine sh
ls /var
cache
empty
lib
local
lock
log
mail
opt
run
spool
tmp

Notice there is no shell prompt. There is no pseudo-terminal, the alpine container is just using the stdin of its parent process. This is not user-friendly for interactive shell sessions inside containers.

-t tells the docker process that input is coming not only from stdin, but specifically a terminal device (aka your shell session), so it allocates a pseudo-terminal for the container.

$ docker run -it alpine sh
/ # ls /var
cache  empty  lib    local  lock   log    mail   opt    run    spool  tmp
/ #

If you remove -t from the docker run command, you are telling docker that you don’t need a pseudo-terminal allocated for the container. You will still be able to type commands into it (for example, Ctrl-C will be read by the container if you want to kill it), but you won’t get a shell prompt.

This is a good post that helped me understand what’s going on.