Docker

如何导出 Docker 镜像

可以使用 docker save 和 docker export 导出 docker 镜像。那么两者有什么区别呢?

  • export 是用来导出一个容器的,也就是运行中的镜像。
  • save 是用来导出镜像的,也就是还没有运行的镜像。

这里我们需要用的显然是 docker save。

语法是:

docker save [OPTIONS] IMAGE [IMAGE...]

其中的 options 也就一个参数 -o 文件名。如果不指定 -o 的话直接输出到 stdout,方便使用管道串联。

如果需要压缩的话还可以这样

docker save myimage:latest | gzip > myimage_latest.tar.gz

导出之后,可以使用 docker load 导入镜像。不使用 -i 的话直接从 stdin 读取。

docker load -i FILE

Docker Compose 教程

使用 docker run 运行容器的时候经常需要加很多的参数,每次都输入这么多参数很容易出错。另外我们经常需要同时运行若干个容器来构成一个服务,此时还是涉及到网络的联通等操作。docker compose 可以把 docker 执行时的参数写成 yaml 文件,运行的时候只需要 docker-compose up -d 一下就可以了。

话不多说,下面通过一个例子来学习一下 docker-compose.yml 文件的语法。

version: "3"  # 版本号,目前最新版是 3,不同版本的语法是不太兼容的
services:  # 定义的服务,注意是一个字典
  web:
    build: .
    environment:  # 定义环境变量
      - ENV=prod
    depends_on:  # 该服务依赖下面的两个服务,也就是指定了
      - db
      - redis
  redis:
    image: redis  # 使用 dockerhub 上的 redis 镜像,这里也可以填自己的私有地址
    ports:
     - "3000"
     - "3000-3005"
     - "8000:8000"
     - "9090-9091:8080-8081"
     - "49100:22"
     - "127.0.0.1:8001:8001"
     - "127.0.0.1:5000-5010:5000-5010"
     - "6060:6060/udp"
  db:
    image: postgres
    volumes:
      - "/var/run/postgres/postgres.sock:/var/run/postgres/postgres.sock"
      - "dbdata:/var/lib/postgresql/data"  # 挂载的库,为了和 yaml 语法兼容,必须用引号

volumes:  # 定义的卷
  - dbdata
  1. version 指定了当前 docker-compose 文件的版本
  2. services 服务列表,是一个 "服务名:配置" 的字典。这里定义了三个服务:
    web/redis/db
  3. build,docker build 命令的参数,用来指定需要构建的 dockerfile
  4. image,如果镜像不需要自己构建,而是使用dockerhub上的基础镜像,可以直接使用
    image 指令
  5. depends_on 指定当前的服务依赖的服务,从而确定启动顺序
  6. ports 开放的端口的数组,有三种形式:
    1. "3000" 容器中开放的端口
    2. "3000:3000" 开放容器中的端口到宿主机
    3. "127.0.0.1:3000:3000" 开放容器中的端口到宿主机并绑定IP
  7. environment 环境变量
  8. volumes 挂载的卷,可以使用named volume或者是挂载目录,建议不要使用匿名卷。如
    果使用 named volume,必须在volumes下声明

运行服务

docker-compose 有以下3个常用命令:

  1. docker-compose up [-d] [SERVICE] 启动服务,-d 表示以 daemon 形式后台运行,并且会在重启后自动启动。
  2. docker-compose run
  3. docker-compose stop

tiller for docker

# Yifei’s Notes

Tiller SUCKS

The only good part of tiller is that it makes a docker image can read environment variables and generate config files based on predefined templates, this functionality should easily be achieved by python and jinja2

# Tiller

tiller runs program such as nginx inside docker instead of bare-bone nginx. tiller dynamically generates config files for different environment such as dev and QA.

tiller is only useful because **your program reads config files only** instead of environment variables

you define variables and pass the variables to tiller, tiller generate config files and the start corresponding program.

Before: Docker -> nginx
After: Docker -> tiller -> nginx

you copy the config file template when building image
and run the container with you env vars

# Downsides

We have to pre-define several environments in the image, then we choose which to use when starting the container.
It’s fine to use if we have limited envs, but what if we want to change the environment, we have to repack the image

docker 小技巧

# 删除所有停止的容器

docker rm `docker ps -aq`

# 删除所有没有 tag 的镜像

docker rmi `docker images | grep “^” | awk ‘{print $3}’`

# 进入运行中的镜像

docker exec -it CONTAINER_NAME bash

# 杀死所有运行中的镜像

docker kill $(docker ps -q)

# 删除所有镜像

docker rmi $(docker images -q)

docker 基础概念

Docker 是一个进程的容器,**不是虚拟机**。他为一个进程隔离了文件系统、网络和环境变量。最好在其中运行一个且仅运行一个线程,而不是运行多个任务。

docker 中最好运行的是无状态的服务,这样方便于横向扩展,对于有状态的服务,建议把状态 mount 出来。

# 使用场景

1. 为有不同需求的应用创建不同的隔离环境, 比如部署两个脚本,一个需要用 Python 2.7,另一个需要用 Python 3.6
2. Micro services. Micro services are easy to scale up. In this way, run only one process in a container, and use orchestration tools such as compose, kubernetes, swarm.
3. Daemon Process Manager. Docker is very simple to use as a daemon process manager, to start and list daemon processes has never been this simple
4. A jail for apps. Docker is good to jail you application, prevent it from hurting your system, especially when you run code from other people(e.g. uploaded by a client)

Docker is so-called kernel containerization, in contrary to user-space containerization such as rkt. Docker stores images in a central base on your machine.

# Image vs Container(镜像与容器)

Container is a running instance of image, each time you run an image, a new container is created. You can commit a container back as an image, however, it’s a little controversial

Image name format: user/image:tag

# basic usage

* `docker run OPTIONS IMAGE COMMAND` to generate a container based on given image and start it.
* most used command is -d
* and -it
* –restart=always to always restart the container
* –name=NAME to name the container
* `docker start CONTAINER_ID` to restart stopped container, note that this will reuse the options and command when `docker run` is issued
* then use `docker attach CONTAINER_ID` to reattach to the given container
* `docker exec OPTIONS CONTAINER COMMAND` to run an extra command in container

Note, docker is all about stdio, and if you would like to read something, read it from stdin, if you would like to output something, write to stdout

# building docker images
two ways:
* commit each change
* using dockerfiles

# Commands

## Container related

### run

每次执行 `docker run`, 都会根据镜像来创建一个全新的 container, 可以使用 `docker start` 或者 `docker attach` 来连接上已经创建的 container。image 和 container 的关系大概类似于程序和进程之间的关系。

Syntax:

`docker run [options] [image name] [command]`
`docker exec -it [container] bash` can be used as a ssh equivalent
`-d` detach the container and runs in background
`-p` set ports [host:container]
`–name` set the name
`–rm` clean the container after running
`–net` sets the network connected to
`-w` sets working dir
`-e` sets env variable
`-u` sets user
`-v` sets volume host_file:container_file:options

### status

`docker ps -a` shows which container is running

## Image ralated

`docker pull`
`docker images`
`docker search`
`docker build` docker build -t user/image [dir]

## 网络相关

基础命令

“`
docker network ls ls the network interfaces
docker network inspect inspect the network for details
docker network create/rm create network interface
docker network connect/disconnect [net] [container] connect a container to a network
“`

by setting network, docker automatically create /etc/hosts file inside the image, and you can use the name of the container to access the others.

docker 有两个网络模式

### 桥接模式

使用 `docker run –net=”bridge”,这种模式会使用虚拟网卡 docker0 做了一层 NAT 转发,所以效率比较低,优点是不用改变应用分配固定端口的代码,docker会在宿主机上随机分配一个端口,避免冲突。

### Host 模式

使用 `docker run –net=”host”,宿主机和docker内部使用的都是同一个网络,比如说 eth0

## 卷

Docker 容器一般来说是无状态的,除了保存到数据库之外,还可以使用卷来把容器中的状态保存出来。

docker volume create –name hello
docker run -d -v hello:/container/path/for/volume container_image my_command

## 日志

You could use `docker logs [contianer]` to view stdout logs. But the logs sent to /var/logs/*.log are by default inside the container.

Remove stopped images
docker rm $(docker ps -aq)

使用docker的时候不使用 sudo

“`
sudo gpasswd -a ${USER} docker
“`

然后登出再登录当前用户即可

# 参考

https://blog.talpor.com/2015/01/docker-beginners-tutorial/

Dockerfile 基础教程

Dockerfile 列出了构建一个docker image 的可复现步骤。比起一步一步通过 docker commit 来制作一个镜像,dockerfile更适用于 CI 自动测试等系统。

Dockerfile 命令

  • FROM,指定基础镜像
  • MAINTAINER,作者,建议格式(Jon Snow <jonsnow@westros.com>
  • EXPOSE,需要暴露的端口,但是一般也会使用 -p 来制定端口映射
  • USER,运行的用户
  • WORKDIR,进程的工作目录
  • COPY,复制文件到
  • RUN,运行shell命令
  • CMD,启动进程使用的命令
  • ENTRYPOINT,镜像启动的入口,默认是 bash -c
  • ENV,设定环境变量
  • VOLUME,卷

几个比较容易混淆的

COPY vs ADD

ADD 会自动解压压缩包,在不需要特殊操作的时候,最好使用COPY。

ENTRYPOINT vs CMD

entrypoint 指定了 Docker 镜像要运行的二进制文件(当然也包括参数),而 cmd 则指定了运行这个二进制文件的参数。不过因为默认 entrypoint 是 bash -c,所以实际上 CMD 指定的也是要运行的命令。

另外,docker run 时候包含命令行参数,会执行命令行参数,而不是 CMD 的内容。如果使用 /bin/bash 作为命令行的指令,这样便替换掉 CMD 的内容,从而进入镜像中查看编译出的镜像究竟是什么样的。

个人倾向于只使用 CMD,而不使用 ENTRYPOINT

如何理解 VOLUME 指令

Dockerfile 中的 volume 指定了一个匿名的 docker volume,也就是说在 docker run 的时候,docker 会把对应的目录mount 到一个匿名的卷。当然如果使用 -v 参数指定了 mount 到哪个目录,或者是指定了卷名,那就不会采用匿名的卷了。

使用Dockerfile 还是 commit 来构建镜像

如果可能的话,尽量使用 dockerfile,因为是可复现的。

I’ve been wondering the same thing, and my impression (which could be totally wrong) it that it’s really the same case as with VMs –> you don’t want to not know how to recreate the vm image. In my case I have regular .sh scripts to install, and am wondering why I can’t just maintain these, run docker and effectively call these, and create the golden version image that way. My scripts work to get it installed on a local PC, and the reason I want to use docker is to deal with conflicts of multiple instances of programs/have clean file system/etc
https://stackoverflow.com/questions/26110828/should-i-use-dockerfiles-or-image-commits

参考

  1. https://stackoverflow.com/a/34245657/1061155
  2. https://stackoverflow.com/questions/41935435/understanding-volume-instruction-in-dockerfile