Docker入门
问题
在公司开发项目的时候,为了避免不出什么幺蛾子,会尽量保证多人的开发环境一致:系统版本,编译器版本,甚至交叉编译器目录都安装成一样的,避免因为环境出错而导致的不必要的成本.一切都运行的很好,直到有次遇到了问题,需要到杜工电脑上编译时,可能编译过多个项目的代码,依赖库的版本也可能和我们的环境不一样,折腾了二十分钟,最后还是在我电脑编译了发给他.
我电脑之前就因为不同项目有依赖同一个软件的不同版本,最后电脑崩了,直接新装了系统.
问题场景:
- 一个人的主机编译不同的项目,不同的项目可能会依赖同一个软件/库的不同版本.有的项目依赖java5,有的依赖java8
- 项目的开发,测试和部署环境不一致.导致:"我这儿都跑的好好的,怎么在你那里运行就有问题"
- 程序部署到不同系统环境的server,(公司的不台服务器装有不同的系统,又或者你把程序发给客户)
前者导致自己维护主机的环境困难,可能会和我一样弄的重装系统;后者导致会增加一些不必要的工作
虚拟机
如果我给一个项目创建一个虚拟机,这个问题就能解决了.这个虚拟机的运行环境专门为这个项目定制的
缺点
- 占用资源高:占CPU,占内存,占磁盘
- 启动慢:需要先启动一个系统
- 共享麻烦:环境共享给别人时,拷贝一个系统实例?
Docker介绍
Docker中的容器是虚拟了操作系统,而虚拟机虚拟了硬件资源
能保证开发,测试,部署的环境一致(编译环境和运行环境),和主机无关的环境
优点
- 占用资源低:用多少给多少
- 启动快:像本地启动一个进程一样快
- 共享方便:共享一个Dockerfile文件;或者共享一个docker hub的链接
- 管理方便:不用就删了
概念
- 镜像image:和虚拟机类比,就是系统镜像文件(里面包括一个程序必要的编译或运行环境)
- 容器container:和虚拟机类比,就是安装好的虚拟机系统
- docker hub:一个下载镜像image的远程仓库,
- Dockerfile文件:一个用于创建镜像image的规则文件(添加软件去年依赖)
安装
官网文档:https://docs.docker.com/get-docker/
Ubuntu安装:
# 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:
- 如果架构不是x86_64/amd64,去看文档找对应的;
- 另外,安装出问题了看官方文档,已官方文档为主,当前安装文档只是官方文档某个时间文档的快照
Windows和MacOS安装:
https://docs.docker.com/get-docker/ 下载对应平台的安装包,然后双击、下一步、下一步、就可以了
Windows和MacOS版本会有界面
配置镜像源
是用来解决docker下载镜像慢问题,使用docker官方的镜像:https://registry.docker-cn.com
Ubuntu:
修改 /etc/docker/daemon.json
文件并添加上 registry-mirrors 键值。(如果文件不存在,请新建该文件)
{
"registry-mirrors": ["https://registry.docker-cn.com"]
}
修改保存后重启 Docker 以使配置生效。Ubuntu重启Docker:
$ sudo systemctl daemon-reload
$ sudo systemctl restart docker
MacOS:
设置-->Docker Engine:
Docker常用命令
帮助命令
$ docker --help
# 查看子命令的help: docker subcommand --help
$ docker image --help
$ docker container --help
镜像image相关命令
Dockerhub:https://hub.docker.com/
# 查看本机的镜像列表
$ 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相关命令
# 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
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" ]
生成镜像
$ docker build -t image_name . # .是指Dockerfile文件所在的目录
通过镜像启动container
$ 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的交叉编译环境,并分发给其它同事,保证统一的编译环境
步骤:
- 启动一个Container实例(image -> container)
- 为项目定制镜像Image,编写Dockerfile(Dockerfile -> image)
- 把交叉编译器和代码映射进去
- 分发共享这个环境(镜像)
启动一个容器Container实例
$ docker run -it --name linux-kit ubuntu:latest bash
# --rm:退出则删除Container
$ docker run -it --rm --name linux-kit ubuntu:latest bash
为项目定制镜像Image,编写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:
$ docker build -t linux-kit:latest . # .是指Dockerfile文件所在的目录
把交叉编译器和代码映射到Container
# 运行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 编译、运行、测试
在次启动和进入容器:
# 方式1:直接启动容器Container,并进入
$ docker start -i linux-kit
# 方式2:先启动容器Container,然后进入
$ docker start linux-kit
$ docker exec -it linux-kit bash
分发共享这个环境(镜像)
共享这一套环境给其它开发人员
分发方式:
- 分发Dockerfile文件
- 上传到Docker hub
- 分发镜像文件:
- 把镜像打包分享
- 把Container打包成镜像分享
分发Dockerfile文件:
一般把Dockerfile文件放在项目根目录下,开发人员自行远程下载,组装镜像环境,配置自己的项目目录,编译器目录
$ 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:
分发镜像文件:
把镜像打包分享
# 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打包成镜像分享
# 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示例
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
启动
$ docker-compose up
VSCode整合Docker
VSCode整合Docker,搭建开发环境
文档:https://code.visualstudio.com/docs/remote/containers
安装插件:Remote - Containers
实现:在Container里面装了一个VS Code Server,