断断续续的使用Docker好几年了,但是一直没有全面深入的去了解过,每次用到都是Google一下相关的命令解决临时的问题,到头来却毫无收获。好在,我终于意识到了这个问题,便决定从头开始,耐心的学学Docker,并把学习过程记录下来,方便以后参考,也望与大家交流学习。
本人比较偏爱Ubuntu,故本文所用命令皆基于Ubuntu 16.04,其他版本的命令会有稍有不同,本文不多做介绍。
目录
简介
容器:将软件打包成标准化单元,以用于开发、交付和部署,而 Docker 是世界领先的软件容器平台。
容器镜像是轻量的、可执行的独立软件包,包含软件运行所需的所有内容:代码、运行时环境、系统工具、系统库和设置。
容器 VS 虚拟机:
容器和虚拟机具有相似的资源隔离和分配优势,但功能有所不同,因为容器虚拟化的是操作系统,而不是硬件,因此容器更容易移植,效率也更高。
-
容器是一个应用层抽象,用于将代码和依赖资源打包在一起。多个容器可以在同一台机器上运行,共享操作系统内核,但各自作为独立的进程在用户空间中运行。与虚拟机相比,容器占用的空间较少(容器镜像大小通常只有几十兆),瞬间就能完成启动。
-
虚拟机 (VM) 是一个物理硬件层抽象,用于将一台服务器变成多台服务器。管理程序允许多个 VM 在一台机器上运行。每个 VM 都包含一整套操作系统、一个或多个应用、必要的二进制文件和库资源,因此占用大量空间。而且 VM 启动也十分缓慢。
安装
准备
首先更新Package索引:
sudo apt-get update
添加Https支持:
sudo apt-get install \\
apt-transport-https \\
ca-certificates \\
curl \\
software-properties-common -y
然后添加Docker官方的GPG key:
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
## 如果上面的地址不能下载,可以使用国内镜像
curl -fsSL https://mirrors.ustc.edu.cn/docker-ce/linux/ubuntu/gpg | sudo apt-key add -
添加Docker-CE稳定版仓储地址:
sudo add-apt-repository \\
"deb [arch=amd64] https://mirrors.ustc.edu.cn/docker-ce/linux/ubuntu \\
$(lsb_release -cs) \\
stable"
由于Docker官方仓储download.docker.com
的访问较慢,故使用了中科大镜像源替代。
安装
最后,便可以直接安装了:
sudo apt-get update
sudo apt-get install docker-ce
我们可以运行一下Hello Word
来验证一下是否安装成功:
sudo docker run hello-world
默认情况下,Docker需要使用root身份来访问,每次都使用sudo
命令较为麻烦,我们可以将当前用户添加到docker
用户组来实现非root用户访问:
sudo usermod -aG docker $USER
重新登录一下,便可以不使用sudo
命令来操作docker了。
镜像加速
默认情况下,Docker镜像是从Docker官方市场store.docker.com
来拉取的,同样非常缓慢,好在Docker官方提供了国内镜像库,可使用如下命令来配置:
docker --registry-mirror=https://registry.docker-cn.com daemon
为了永久性保留更改,可以修改/etc/docker/daemon.json
文件并添加上 registry-mirrors 键值:
{
"registry-mirrors": ["https://registry.docker-cn.com"]
}
修改保存后重启 Docker 以使配置生效:
sudo systemctl restart docker
安装Docker Compose
Docker Compose 是一个用来定义和运行复杂应用的Docker工具。我们的应用通常会由多个容器组成,使用Docker Compose可以非常容易的将一组容器当成一个整体来配置部署。
curl -L https://github.com/docker/compose/releases/download/1.23.2/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose
chmod +x /usr/local/bin/docker-compose
可以在 https://github.com/docker/compose/releases 查看具体的发布列表。
常用命令
运行容器(run)
run是我们最常用的命令:
docker run nginx
如上,便启动了一个nginx
容器。
端口映射(-p)
此时,我们还无法通过访问宿主机的IP来访问刚才部署的Nginx,需要先进行端口映射:
docker run -p 8080:80 nginx
后台运行(-d)
默认情况下,当我们推出命令行时,容器也会被关闭。我们可以使用-d
参数使容器保持后台运行:
docker run -d <image-name>
然后访问宿主机的IP:8080,便可以看到“Welcome to nginx!”。
指定名称(-n)
docker run --name <container-name> <image-name>
docker run --name myredis redis
如上,创建了一个名称为redis
的容器。
持久化数据(-v)
容器被设计为无状态的,当我们删除一个容器时,保存在其中的数据也会随之删除。如果我们希望某些数据不随着容器的删除而删除,则可以使用目录绑定(通常称为卷),将容器中的某个文件夹于主机上的文件夹绑定,来实现数据的持久化。
docker run -v <host-dir>:<container-dir> <image-name>
除此之外,我们还可以使用Data Containers
来实行数据的持久化,数据容器(Data Containers)唯一的职责就是存储和管理数据:
docker create -v /config --name dataContainer busybox
如上,我们使用busybox
镜像创建了一个数据容器,并使用-v
参数来指定容器存储和管理数据的目录位置。
然后我们可以将文件拷贝到容器中:
docker cp config.conf dataContainer:/config/
接下来,我们就可以在新的容器中引用该数据容器了:
docker run --volumes-from dataContainer ubuntu
新创建的ubuntu
容器挂载了数据容器的/config
目录。
重启策略(--restart)
通过--restart
选项,可以设置容器的重启策略,以决定在容器退出时Docker守护进程是否重启刚刚退出的容器。
docker run -d --restart=always <image-name>
有如下4种重启策略:
- no,默认策略,在容器退出时不重启容器
- on-failure,在容器非正常退出时(退出状态非0),才会重启容器
- on-failure:3,在容器非正常退出时重启容器,最多重启3次
- always,在容器退出时总是重启容器
- unless-stopped,在容器退出时总是重启容器,但是不考虑在Docker守护进程启动时就已经停止了的容器
进入交互模式(-it)
docker run -it [image-name] /bin/bash
- -i interact 进入交互模式。
- -t tty 分配一个伪终端。
执行之后,可以看到命令行的主机名已经变成了容器的Id,表示成功进入到了容器中,可以使用exit
命令退出容器。
其他
# 启动一个SQLServer容器
docker run -e \'ACCEPT_EULA=Y\' -e \'SA_PASSWORD=Qwer1234\' -p 1433:1433 -d --restart=unless-stopped microsoft/mssql-server-linux
管理容器
查看容器(ps)
docker ps
通过ps
命令可以看到当前运行的容器,添加-a
参数,则可以看到停止的容器。
我们可以使用docker inspect <friendly-name|container-id>
来查看某个容器的详细信息:
dokcer inspect redis
附加容器(attach)
ttach可以附加到一个已经运行的容器的stdin中。
docker attach [containerid]
进入容器(exec)
docker exec -it [containerid] /bin/bash
是需要注意的是,对于attach
,如果从这个stdin中exit,会导致容器的停止。而exec
则不会,推荐使用exec
。
停止容器(stop)
docker stop [containerid]
删除容器(rm)
docker rm [containerid]
如果要删除的容器正在运行,则无法删除,可以添加-f
参数来强制删除,也可以先停止容器再删除:
如果我们想删除所有的容器,可以使用如下命令:
docker rm $(docker ps -a -q) -f
镜像管理
Docker把应用程序及其运行环境等打包在 image 文件里面,相当于容器的模板。
搜索镜像
我们可以在 registry.hub.docker.com 查找镜像,也可以使用 dokcer search <name>
命令来搜索,如:我们使用如下命令来搜索redis
镜像。
docker search redis
查看镜像
# 查看镜像列表
docker images
# 查看所有镜像(包括中间层镜像)
docker image -a
# 查看所有镜像的ID
docker images -q
# 查看所有的虚悬镜像(-f 显示满足条件的镜像)
docker images -f "dangling=true"
# 按仓库名过滤
docker images [REPOSITORY]
# 按仓库名和标签过滤
docker images [REPOSITORY:TAG]
镜像列表输出如下:
REPOSITORY | TAG | IMAGE ID | CREATED | SIZE |
---|---|---|---|---|
hello-world | latest | e38bc07ac18e | 2 weeks ago | 1.85kB |
每列含义:
- REPOSITORY:仓储名
- TAG:标签, 一个镜像可以有多个标签
- IMAGE ID:镜像的唯一标识,通常在删除镜像时使用
- CREATED:创建时间
- SIZE:所占用的空间,展开后的各层所占空间的总和。
删除镜像
# 删除镜像
docker rmi [imageid]
docker image rm [imageid]
# 删除所有镜像
docker image rm $(docker images -q) -f
# 删除虚悬镜像(dangling image)
docker image prune
仓库名和标签均为<none>
,这类无标签、无仓储名的镜像被称为dangling image
。
拉取推送
# 拉取镜像
docker pull [imagename]
# 构建镜像
docker build
# 推送镜像
docker push [imagename]
其他
# 查看镜像、容器、卷占用的空间
docker system df
Dockerfile
Dcoker镜像是从一个基础镜像开始的,基础镜像包括应用程序所需的平台依赖项, 例如, 安装了JVM
或CLR
等。
镜像的定义是使用dockerfile
文件来表达的。dockerfile
是描述如何部署应用的列表。一个简单的Dockerfile
文件如下:
FROM nginx:alpine
COPY . /usr/share/nginx/html
如上,我们的基础镜像是一个alpine版本的nginx
,从而拥有了一个安装了nginx
的linux环境。
接下来,我们可以通过定义的dockerfile
文件来构建镜像:
docker build -t webserver-image:v1 .
其-t
参数为镜像指定一个友好的名字和标记,.
则表示使用当前目录的dockerfile
文件。
OnBuild
通常,dockerfile
文件的执行顺序是从上到下,但我们可以使用ONBUILD
指令来延后执行(在子镜像构建时执行)。
如下,我们定义一个经典的Node
应用程序基础镜像:
FROM node:10
RUN mkdir -p /usr/src/app
WORKDIR /usr/src/app
ONBUILD COPY package.json /usr/src/app/
ONBUILD RUN npm install
ONBUILD COPY . /usr/src/app
CMD [ "npm", "start" ]
当我们构建该镜像时,ONBUILD
指令包含的内容将不会执行,然后我们定义一个该镜像的子镜像:
FROM node:10-onbuild
EXPOSE 3000
当我们构建该镜像时,上面的ONBUILD
才会被执行。这样做的优势是可以在多个镜像中共享一份基础镜像,大大减少构建的速度。
Ignore File
为了防止将一个不必要或者敏感的数据打包到镜像中,可以使用.dockerignore
文件进行配置。
下面的命令将passwords.txt
文件加到了忽略中,确保它不会意外的被打包到镜像中发布出去。
echo passwords.txt >> .dockerignore
我们可以将.dockerignore
文件存储在源代码管理中,保持团队间的一致。
总结
Docker是革命性的,干净利落的UX俘获了技术人员的芳心,ASP.NET Core 也是全面拥抱Docker,我们也要紧跟时代的步伐。
本文主要介绍docker的一些基本用法,可作为一个docker使用笔记来参考,并不断的补充完善,但不会涉及到比较深入的介绍,后续在其他文章中会详细介绍一些具体的用法。