文章目录

  • Introduction
  • Docker的兼容性问题
  • Docker网络
  • 构建一个最简单包,推送到Registry上
  • Docker Cheatsheet
  • Image
  • 拉取镜像
  • Docker镜像加速
  • 本地导入导出Docker镜像
  • 将运行中的容器变成镜像
  • 列出镜像
  • 在远程主机构建docker镜像
  • Systemd
  • 增加docker远程访问选项
  • 远程构建镜像
  • 支持中文
  • 容器挂载NFS远程文件系统
  • Linux OS 容器挂载
  • Windows OS 容器(Linux模式容器)挂载
  • Docker Compose
  • bind mount
  • 本地目录
  • nfs


本文记录使用docker的常用技巧

Introduction

镜像(Image)和容器(Container)的关系,就像是面向对象程序设计中的 类 和 实例 一样,镜像是静态的定义,容器是镜像运行时的实体。容器可以被创建、启动、停止、删除、暂停等。

3CDaemon配置备份_3CDaemon配置备份

此图转载自:

简单来讲,之前开发一个Python应用,首先需要在机器上安装Python环境。
但是,使用docker,只需要一条命令就可以运行python应用,即:

docker run -p 4000:80 username/repository:tag

镜像里有python的运行时环境,还有一些依赖包。

Docker的兼容性问题

参考:How much does Docker virtualize?

这个问题首先出现在我将x86架构构建的镜像在arm架构上面。

Standard_init_linux.go:190: exec user process caused “exec format error

这涉及到Docker到底抽象到什么程度。Docker容器可以相同芯片架构上机器运行。也就是,你可以在x86_64架构的机器上,运行x86架构主机上构建的镜像。

docker只不过利用了linux的公用内核,即使这么多版本(ubuntu,centos,alpine,suse),但是它们的内核都是一样的。没有这一层共同的部分,要想实现通用可移植是不可能的。

即使windows上已经支持docker,也是需要一部分linux内核。可以参考Preview: Linux Containers on Windows

抛开docker,在x86_64编译的二进制文件无法运行于ARM架构的机器上。这是因为两种芯片指令集都不相同。docker的抽象仅限抽象linux内核之上的东西,那涉及到linux之下的东西是不能移植的。

我画一张图来表示docker的抽象的部分,仅仅是把你语言的运行时环境,依赖包都放进去而已。

开发docker的初衷也是因为开发环境和生产环境用的linux版本不同而发现的。随着docker声名鹊起好像抽象功能被放大了一样,其实那都是幻象。docker仅原生支持linux类型系统,像macOS(UNIX),windows,freeBSD这些是不行的;这些都是需要使用插入linux内核的方式去兼容的(docker公司好像在努力推进这个事情…)

3CDaemon配置备份_运维_02

Docker网络

参考:docker网络

构建一个最简单包,推送到Registry上

# 本地当前目录构建
docker build --tag=friendlyhello:v0.0.1 .
# 查看已构建包
docker image ls
# 运行已构建包
docker run -p 4000:80 friendlyhello
# 登陆
docker login
# 为本地已构建包贴标签
docker tag image username/repository:tag
docker tag friendlyhello gordon/get-started:part2
# 推送到docker registry
docker push username/repository:tag
# 拉取并在任何联网机器运行
docker run -p 4000:80 username/repository:tag

镜像的依赖关系,docker镜像构建时的.Dockerfile都会指定本镜像基于的镜像(base image)。新的Docker镜像包含基础镜像的全部文件。比如可以基于ubuntu打包一个带jdk的ubuntu镜像ubuntu-jdk,然后基于ubuntu-jdk打包一个带有tomcat的镜像。

Docker Cheatsheet

# 查看全部运行的容器
docker ps
# 前台运行容器
docker run <image_name>
#后台(daemon)运行容器
docker run -d <image_name>
# 切入容器内部
docker exec -it <container_name> bash
# 端口映射
docker run  -d -p <host_port>:<container_port> <image_name>

Image

拉取镜像

docker pull <username>/<repository>:tag

比如:

3CDaemon配置备份_Docker_03

Docker镜像加速

/etc/docker/daemon.json

{
  "registry-mirrors": ["http://hub-mirror.c.163.com"]
}

本地导入导出Docker镜像

Docker镜像可以使用保存到.tar包。

docker image save helloworld > helloworld.tar

tar包可以重新导入为docker镜像。

docker image load -i helloworld.tar

将运行中的容器变成镜像

有些场景下,你对容器做出一些通用性的更改,需要将运行中的容器变成镜像:

docker commit -a='author oneslide' -m='your custom message' container_name image_tag

如:

# 将运行中容器名(容器名在docker run 时使用--name指定)为 my-sample-app 的容器变成镜像,镜像的tag是oneslide/tomcat 
docker commit -a='author oneslide' -m='your custom message' my-sample-app oneslide/tomcat

列出镜像

docker images --format "{{.Repository}}:{{.Tag}}"

输出:

quay.io/prometheus-operator/prometheus-config-reloader:v0.53.1
quay.io/prometheus-operator/prometheus-operator:v0.53.1
quay.io/prometheus/prometheus:latest

另外会有其他的变量,可以用于镜像的格式化输出:

Placeholder

Description

.ID

The ID of your image

.Repository

The image repository

.Tag

The tag of your image

.Size

The size of your image

.CreatedSince

The time since your image was created

.CreatedAt

The point in time when your image was created

.Digest

The digest of your image (in short their UUIDs)

仅列出镜像的ID

docker images -q

在远程主机构建docker镜像

参考:Daemon socket option

Systemd
增加docker远程访问选项

systemd启动文件控制如何启动docker进程,默认情况下,docker进程只允许root用户通过unix local socket连接。需要修改其增加tcp远程访问的配置:

$ vim /usr/lib/systemd/system/docker.service
[Service]
Type=notify
# 这里增加tcp选项
ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock -H tcp://0.0.0.0:2375
ExecReload=/bin/kill -s HUP $MAINPID
TimeoutSec=0
RestartSec=2
Restart=always
远程构建镜像

然后你就可以远程构建镜像和推送:

# 远程构建镜像
docker -H tcp://192.168.10.20:2375 build -t sampleimg:v1 .
# 远程推送镜像,客户端机器和构建机器都要登录私库
docker -H tcp://192.168.10.20:2375 push 172.16.67.139/cicd/remotebuild:v1

支持中文

# centos 设置环境变量
ENV LANG="en_US.UTF-8"

容器挂载NFS远程文件系统

Linux OS 容器挂载

nfs直接挂载为本地目录就可以了

mount -t nfs <ip>:/<源主机目录> <本机目标目录>

直接使用-v挂载即可。

Windows OS 容器(Linux模式容器)挂载

  1. nfs服务器创建一个所有人可读写的目录:
/docker-test2 *(rw,sync,insecure,no_subtree_check,no_root_squash)

运行exportfs -rv生效

  1. 创建Named Volume
docker volume create --driver local --opt type=nfs \
 --opt o=addr=192.168.10.8,hard,nolock,rw --opt device=:/源主机目录 mynfs

使用命名Volume方式挂载

# 此处nfs为volume name
docker run -d --name test -v mynfs:/etc/nginx/conf.d nginx

Docker Compose

bind mount

本地目录

Host volumes: For a host volume, defined with a path in your docker compose file like:

volumes:
  - "./wordpress/uploads:/var/www/html/wp-content/uploads"

you will not receive any initialization of the host directory from the image contents. This is by design.

Named volumes: You can define a named volume that maps back to a local directory:

version: "2"

services:
  your-service:
    volumes:
      - uploads:/var/www/html/wp-content/uploads

volumes:
  uploads:
    driver: local
    driver_opts:
      type: none
      o: bind
      device: /path/on/host/to/wordpress/uploads

This will provide the initialization properties of a named volume. When your host directory is empty empty, on container creation docker will copy the contents of the image at /var/www/html/wp-content/uploads to /path/on/host/to/wordpress/uploads.

这种模式下目录不会自动创建(e.g. /path/on/host/to/wordpress/uploads)。

nfs

version: "3.9"

services:
  web:
    image: cicd-nginx:1.21.0
    volumes:
      - web:/etc/nginx/templates
    ports:
      - "8081:8083"
    environment:
      - NGINX_HOST=foobar.com
      - NGINX_PORT=8083
volumes:
  web:
    driver: local
    driver_opts:
      type: nfs
      o: addr=192.168.10.20,hard,nolock,rw
      # 前面必须要加:
      device: :/nginx/data