Skip to content
Published at:

Docker入门

问题

在公司开发项目的时候,为了避免不出什么幺蛾子,会尽量保证多人的开发环境一致:系统版本,编译器版本,甚至交叉编译器目录都安装成一样的,避免因为环境出错而导致的不必要的成本.一切都运行的很好,直到有次遇到了问题,需要到杜工电脑上编译时,可能编译过多个项目的代码,依赖库的版本也可能和我们的环境不一样,折腾了二十分钟,最后还是在我电脑编译了发给他.

我电脑之前就因为不同项目有依赖同一个软件的不同版本,最后电脑崩了,直接新装了系统.

问题场景:

  • 一个人的主机编译不同的项目,不同的项目可能会依赖同一个软件/库的不同版本.有的项目依赖java5,有的依赖java8
  • 项目的开发,测试和部署环境不一致.导致:"我这儿都跑的好好的,怎么在你那里运行就有问题"
  • 程序部署到不同系统环境的server,(公司的不台服务器装有不同的系统,又或者你把程序发给客户)

前者导致自己维护主机的环境困难,可能会和我一样弄的重装系统;后者导致会增加一些不必要的工作

虚拟机

如果我给一个项目创建一个虚拟机,这个问题就能解决了.这个虚拟机的运行环境专门为这个项目定制的

缺点

  • 占用资源高:占CPU,占内存,占磁盘
  • 启动慢:需要先启动一个系统
  • 共享麻烦:环境共享给别人时,拷贝一个系统实例?

Docker介绍

官网:https://www.docker.com/

Docker中的容器是虚拟了操作系统,而虚拟机虚拟了硬件资源

保证开发,测试,部署的环境一致(编译环境和运行环境),和主机无关的环境

优点

  • 占用资源低:用多少给多少
  • 启动快:像本地启动一个进程一样快
  • 共享方便:共享一个Dockerfile文件;或者共享一个docker hub的链接
  • 管理方便:不用就删了

概念

  • 镜像image:和虚拟机类比,就是系统镜像文件(里面包括一个程序必要的编译运行环境)
  • 容器container:和虚拟机类比,就是安装好的虚拟机系统
  • docker hub:一个下载镜像image的远程仓库,
  • Dockerfile文件:一个用于创建镜像image的规则文件(添加软件去年依赖)

安装

官网文档:https://docs.docker.com/get-docker/

Ubuntu安装:

bash
# 1.Update the apt package index and install packages to allow apt to use a repository over HTTPS:
$ sudo apt-get update
$ sudo apt-get install \
    apt-transport-https \
    ca-certificates \
    curl \
    gnupg \
    lsb-release

# 2.Add Docker’s official GPG key:
$ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg

# 3.添加源(注意:当前是x86_64/amd64,其它的请参考官方文档)
$ echo \
  "deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu \
  $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

# 4.安装docker
$ sudo apt-get install docker-ce docker-ce-cli containerd.io

Note:

  1. 如果架构不是x86_64/amd64,去看文档找对应的;
  2. 另外,安装出问题了看官方文档,已官方文档为主,当前安装文档只是官方文档某个时间文档的快照

Windows和MacOS安装:

https://docs.docker.com/get-docker/ 下载对应平台的安装包,然后双击、下一步、下一步、就可以了

Windows和MacOS版本会有界面

配置镜像源

是用来解决docker下载镜像慢问题,使用docker官方的镜像:https://registry.docker-cn.com

Ubuntu:

修改 /etc/docker/daemon.json 文件并添加上 registry-mirrors 键值。(如果文件不存在,请新建该文件)

javascript
{
    "registry-mirrors": ["https://registry.docker-cn.com"]
}

修改保存后重启 Docker 以使配置生效。Ubuntu重启Docker:

bash
$ sudo systemctl daemon-reload
$ sudo systemctl restart docker

MacOS:

设置-->Docker Engine:

Docker常用命令

帮助命令

bash
$ docker --help

# 查看子命令的help: docker subcommand --help
$ docker image --help
$ docker container --help

镜像image相关命令

Dockerhub:https://hub.docker.com/

bash
# 查看本机的镜像列表
$ docker images

# pull/push
# docker pull [OPTIONS] NAME[:TAG|@DIGEST]
$ docker pull image_name # 从docker hub拉取Ubuntu镜像
$ docker push image_name # 把本地镜像推到docker hub (可能需要用docker tag先重命令,需要和docker hub中的同名)

# 新建一个tag
$ docker tag SOURCE_IMAGE[:TAG] TARGET_IMAGE[:TAG]

# 保存/导入镜像(共享给其它人同一个环境)
$ docker save -o ubuntu.tar ubuntu20
$ docker import ubuntu.tar ubuntu20_import:latest

# rm image
$ docker rmi image_name

容器container相关命令

bash
# docker run [OPTIONS] IMAGE
# 用某个镜像image创建container
$ docker run --name ubuntu20 -d ubuntu

# 基于镜像ubuntu,创建名为ubuntu20的容器,并以交互的模式启动容器ubuntu20
# 	-name:指定创建的容器名为ubuntu20
#		-i:交互模式运行
#   -t:分配一个终端
$ docker run --name ubuntu20 \
    -i -t ubuntu

# 基于镜像ubuntu,创建名为ubuntu20的容器,并以交互的模式启动容器ubuntu20
#   -w:指定工作目录,进入到容器之后的目录
#   -v:把本机的目录/home/shibin/repo/linux-kit,映射到容器的目录/workspace/linux-kit
$ docker run --name ubuntu20 \
    -w /workspace/linux-kit \
    -v /home/shibin/repo/linux-kit:/workspace/linux-kit \
    -it ubuntu # 创建一个容器container,并启动容器container,以交互的方式运行


# 查看当前container的状态
$ docker ps -a

# 启动
$ docker start container_name/id    # 启动一个容器container
$ docker start -i container_name/id # (i/interactive)启动一个容器container,交互模式运行
$ docker restart container_name/id  # 重启

# 进入到正在运行的container
$ docker exec -it webserver bash
$ docker attach container_name/id

# 将容器保存为镜像
# -a 作者
# -m message
$ docker commit -a shibin -m "linux-kit dev env" cb9050bdc3cc linux-kit:latest

# 停止
$ docker stop container_name/id

# 删除容器container
$ docker rm container_name/id

# 查看容器运行的log
$ docker logs container_name/id    # 查看下log,并退出
$ docker logs -f container_name/id # (f/follow)查看log,不退出

Dockerfile相关命令和语法

文档:https://docs.docker.com/engine/reference/builder/

Dockerfile是由一系列命令和参数构成的脚本,这些命令应用于基础镜像并最终创建一个新的镜像。

语法:

  • FROM:定义使用哪个为基础镜像
  • RUN:执行shell命令
  • ENV:设置环境变量
  • COPY:将主机的文件复制到容器内
  • ADD:更高级的复制文件,如果 <源路径> 为一个 tar 压缩文件的话,压缩格式为 gzip, bzip2 以及 xz 的情况下,会解压
  • VOLUME:将主机的文件映射到容器内
  • EXPOSE:声明容器运行时提供服务的端口
  • WORKDIR:工作目录
  • CMD:最后执行的命令

Dockerfile文件example

dockerfile
FROM ubuntu:20.04

RUN  apt-get update \
    && export DEBIAN_FRONTEND="noninteractive" \
    && apt-get install -y locales build-essential cmake cppcheck valgrind gdb vim \
    && apt-get autoremove -y \
    && apt-get clean -y \
    && rm -rf /var/lib/apt/lists/* \
    && localedef -i en_US -c -f UTF-8 -A /usr/share/locale/locale.alias en_US.UTF-8

COPY /opt/arm-linux-gnueabihf /opt/arm-linux-gnueabihf

ENV PATH="/opt/arm-linux-gnueabihf/bin:${PATH}"
ENV LANG=en_US.utf8

WORKDIR /workspace/linux-kit

CMD [ "echo", "hello dockerfile" ]

生成镜像

bash
$ docker build -t image_name . # .是指Dockerfile文件所在的目录

通过镜像启动container

bash
$ docker run --name container_name \
    -w /workspace/linux-kit \
    -v /home/shibin/repo/linux-kit:/workspace/linux-kit \ # 映射项目代码
    -it ubuntu \
    bash -c "echo hello container"

总结:镜像是用来构建程序的编译或运行环境,在运行项目的时候把代码映射进去

Docker实践

目标:构建Linux-kit的交叉编译环境,并分发给其它同事,保证统一的编译环境

步骤:

  1. 启动一个Container实例(image -> container)
  2. 为项目定制镜像Image,编写Dockerfile(Dockerfile -> image)
  3. 把交叉编译器和代码映射进去
  4. 分发共享这个环境(镜像)

启动一个容器Container实例

bash
$ docker run -it --name linux-kit ubuntu:latest bash

# --rm:退出则删除Container
$ docker run -it --rm --name linux-kit ubuntu:latest bash

为项目定制镜像Image,编写Dockerfile

Dockerfile文件:

dockerfile
FROM ubuntu:20.04

RUN  apt-get update \
    && export DEBIAN_FRONTEND="noninteractive" \
    && apt-get install -y locales build-essential cmake cppcheck valgrind gdb vim \
    && apt-get autoremove -y \
    && apt-get clean -y \
    && rm -rf /var/lib/apt/lists/* \
    && localedef -i en_US -c -f UTF-8 -A /usr/share/locale/locale.alias en_US.UTF-8

COPY /opt/arm-linux-gnueabihf /opt/arm-linux-gnueabihf

ENV PATH="/opt/arm-linux-gnueabihf/bin:${PATH}"
ENV LANG=en_US.utf8

WORKDIR /workspace/linux-kit

CMD [ "echo", "hello dockerfile" ]

构建镜像image:

bash
$ docker build -t linux-kit:latest . # .是指Dockerfile文件所在的目录

把交叉编译器和代码映射到Container

bash
# 运行Container环境;把编译器,代码mount上去
$ docker run -it \
    -v /opt/arm-linux-gnueabihf:/opt/arm-linux-gnueabihf \
    -v /home/shibin/repo/linux-kit:/workspace/linux-kit \
    --env PATH=/opt/arm-linux-gnueabihf/bin:$PATH \
    --name linux-kit linux-kit:latest \
    bash

# 如果上一步成功,会进入到容器内
# bash CMD: do something what you want 编译、运行、测试

在次启动和进入容器:

bash
# 方式1:直接启动容器Container,并进入
$ docker start -i linux-kit

# 方式2:先启动容器Container,然后进入
$ docker start linux-kit
$ docker exec -it linux-kit bash

分发共享这个环境(镜像)

共享这一套环境给其它开发人员

分发方式:

  1. 分发Dockerfile文件
  2. 上传到Docker hub
  3. 分发镜像文件:
    • 把镜像打包分享
    • 把Container打包成镜像分享

分发Dockerfile文件:

一般把Dockerfile文件放在项目根目录下,开发人员自行远程下载,组装镜像环境,配置自己的项目目录,编译器目录

bash
$ docker run -it \
    -v /opt/arm-linux-gnueabihf:/opt/arm-linux-gnueabihf \
    -v /home/shibin/repo/linux-kit:/workspace/linux-kit \
    --env PATH=/opt/arm-linux-gnueabihf/bin:$PATH \
    --name linux-kit linux-kit:latest \
    bash

最佳实践:本地的项目文件或是交叉编译器文件,建议映射(mount)到容器中,不建议拷贝进去。文件都本地方便管理,项目文件方便代码版本管理,Image和Container的性质是:不用随时可以删除。

上传到Docker hub:

todo:

分发镜像文件:

把镜像打包分享
bash
# 1.保存镜像linux-kit到linux-kit.tar
$ docker save -o linux-kit.tar linux-kit

# 2.从linux-kit.tar导入镜像,新的镜像名是linux-kit
$ docker import linux-kit.tar linux-kit:latest
把Container打包成镜像分享
bash
# 1.把Container(cb9050bdc3cc)保存为镜像linux-kit:latest
$ docker commit \
    -a shibin \
    -m "linux-kit dev env" \
    cb9050bdc3cc linux-kit:latest

# 2.保存镜像linux-kit到linux-kit.tar
$ docker save -o linux-kit.tar linux-kit

# 3.从linux-kit.tar导入镜像,新的镜像名是linux-kit:latest
$ docker import linux-kit.tar linux-kit:latest

Docker compose

文档:https://docs.docker.com/compose/

如果容器多了,管理就成了问题,启动的命令也这么长,不可能一个个的敲,把这些写到配置文件docker-compose.yml里面,

一个简单的命令就能开启一个或多个container

docker-compose.yml示例

yaml
version: '3.4'

services:
  service_name:
    image: image_name
    volumes:
      - /home/shibin/repo/linux-kit:/workspace/linux-kit
    working_dir: /workspace/linux-kit
    command: bash -c "echo hello docker-compose"
  redis:
  	xxx
  mysql:
  	xxx

启动

bash
$ docker-compose up

VSCode整合Docker

VSCode整合Docker,搭建开发环境

文档:https://code.visualstudio.com/docs/remote/containers

安装插件:Remote - Containers

实现:在Container里面装了一个VS Code Server,

Reference:

书籍:Docker-从入门到实践

Updated at: