Docker简介
- Docker是一个开源的容器引擎,他有助于更快的交付应用。Docker可以将应用程序和基础设施层做隔离,并且能将基础设施当做程序一样进行管理。使用Docker,可以更快的打包,测试以及部署应用程序,并且可以缩短从编写到部署运行的代码调试周期。
Docker官网
Docker 的GitHub
Docker 的架构
- 以下是Docker官方文档的架构图
- Docker daemon(Docker守护进程):Docker daemon是一个运行在宿主机(DOCKER_HOST)的后台进程。可以通过Docker客户端与Docker daemon进行通信
- Client (Docker 客户端): Docker客户端是Docker的用户界面,他可以接受用户命令和配置标识,并与Docker daemon通信。途中,Docker build 等都是Docker的相关命令
- Images(Docker 的镜像):Docker镜像是一个只读的模板,他包含创建Docker容器的说明。他和系统安装光盘有点像----使用系统安装光盘可以安装系统,同理,使用Docker镜像可以运行Docker镜像中的程序。
- Container(容器):容器是镜像的可运行实例。镜像和容器的关系有点类似面向对象中的,类之于对象的关系。可通过Docker API或者CLI命令来启动停止,移动,删除容器。
- Registry(类似代码仓库):Docker Registry是一个集中存储于分发镜像的服务。构建完Docker镜像后,就可以在当前宿主机上运行。如果想在其他机器上运行这个镜像,需要手动负责,或者借助Docker Registry来避免负责,经Docker镜像push到Docker Registry上,然后在其他机器上pull对应镜像。
Docker安装
- 准备Ubuntu系统,或者虚拟机,安装程序可参照网址
安装Docker
- 官方Ubuntu存储库中提供的Docker安装包,但是可能不是最新的版本,为了确保获取最新版,我们将从Docker官网存储库安装Docker。因此,我们需要添加一个新的资源包,从Docker添加GPG以确保下载有效,然后安装该包:
- 首先更新现有包列表,新安装的ubuntu这个步骤可能会久一点:
sudo apt update
- 接下来使用按apt 安装一下运行通过HTTPS才能使用的软件包
sudo apt install apt-transport-https
sudo apt install ca-certificates
sudo apt install curl
sudo apt install software-properties-common
- 将官方Docker存储的GPG秘钥添加到系统:
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
- 将Docker存储库添加到APT源:
sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu bionic stable"
- 接下来,使用新添加的repo源中的Docker包更新数据库:
sudo apt update
- 确保从Docker repo安装,而不是默认的Ubuntu repo:
apt-cache policy docker-ce
- 看到如下的输出,说明是成功的,版本不同输出的日志应该有一点点差异:
docker-ce:Installed: (none)Candidate: 5:19.03.12~3-0~ubuntu-bionicVersion table:5:19.03.12~3-0~ubuntu-bionic 500500 https://download.docker.com/linux/ubuntu bionic/stable amd64 Packages
- 现在Docker-ce还没有安装,用上面这个命令我们能看到安装源来自Docker官方存储库,最后安装Docker:
sudo apt install docker-ce
- 现在Docker已经安装好了,检查一下是否正常运行:
sudo systemctl status docker
- 有类似如下的输出,标准状态正常:
● docker.service - Docker Application Container EngineLoaded: loaded (/lib/systemd/system/docker.service; enabled; vendor preset: eActive: active (running) since Tue 2020-07-21 00:07:42 PDT; 34s agoDocs: https://docs.docker.comMain PID: 20120 (dockerd)Tasks: 8CGroup: /system.slice/docker.service└─20120 /usr/bin/dockerd -H fd:// --containerd=/run/containerd/contai
- Docker不仅仅提供Docker服务,还提供了Docker命令行工具或者Docker客户端。
非Sudo执行Docker命令
- 默认情况下,Docker命令只能Root用户或者Docker组中用户运行,改用户在Docker安装过程中自动创建,如果想要不使用Sudo运行,或不在docker组中的用户运行会有错误提示信息:
docker: Cannot connect to the Docker daemon. Is the docker daemon running on this host?.
See 'docker run --help'.
- 想要在运行docer时候不输入sudo,需要将用户添加到docker组中,首先创建docker用户组
sudo groupadd docker
- 将用户添加到docker用户组
sudo usermod -aG docker ${USER_NAME}
- 重启docker服务
sudo systemctl restart docker
使用Docker命令
- 以下我都用的root用户来执行,Docker命令使用包括传递一系列docker选项和命令,后跟参数。语法格式如下:
docker [option] [command] [arguments]
- 查询所有子命令输入 docker,有如下:
Commands:attach Attach local standard input, output, and error streams to a running containerbuild Build an image from a Dockerfilecommit Create a new image from a container's changescp Copy files/folders between a container and the local filesystemcreate Create a new containerdiff Inspect changes to files or directories on a container's filesystemevents Get real time events from the serverexec Run a command in a running containerexport Export a container's filesystem as a tar archivehistory Show the history of an imageimages List imagesimport Import the contents from a tarball to create a filesystem imageinfo Display system-wide informationinspect Return low-level information on Docker objectskill Kill one or more running containersload Load an image from a tar archive or STDINlogin Log in to a Docker registrylogout Log out from a Docker registrylogs Fetch the logs of a containerpause Pause all processes within one or more containersport List port mappings or a specific mapping for the containerps List containerspull Pull an image or a repository from a registrypush Push an image or a repository to a registryrename Rename a containerrestart Restart one or more containersrm Remove one or more containersrmi Remove one or more imagesrun Run a command in a new containersave Save one or more images to a tar archive (streamed to STDOUT by default)search Search the Docker Hub for imagesstart Start one or more stopped containersstats Display a live stream of container(s) resource usage statisticsstop Stop one or more running containerstag Create a tag TARGET_IMAGE that refers to SOURCE_IMAGEtop Display the running processes of a containerunpause Unpause all processes within one or more containersupdate Update configuration of one or more containersversion Show the Docker version informationwait Block until one or more containers stop, then print their exit codes
- 查看有关Docker的系统信息:
docker info
- 搜索镜像:
socker search java
- 执行后可以看到如下表格信息
NAME DESCRIPTION STARS OFFICIAL AUTOMATED
node Node.js is a JavaScript-based platform for s… 9044 [OK]
tomcat Apache Tomcat is an open source implementati… 2785 [OK]
openjdk OpenJDK is an open-source implementation of … 2347 [OK]
java Java is a concurrent, class-based, and objec… 1976 [OK]
ghost Ghost is a free and open source blogging pla… 1221 [OK]
couchdb CouchDB is a database that uses JSON for doc… 358 [OK]
jetty Jetty provides a Web server and javax.servle… 340 [OK]
groovy Apache Groovy is a multi-faceted language fo… 97 [OK]
lwieske/java-8 Oracle Java 8 Container - Full + Slim - Base… 46 [OK]
nimmis/java-centos This is docker images of CentOS 7 with diffe… 42 [OK]
fabric8/java-jboss-openjdk8-jdk Fabric8 Java Base Image (JBoss, OpenJDK 8) 28 [OK]
frekele/java docker run --rm --name java frekele/java 12 [OK]
fabric8/java-centos-openjdk8-jdk Fabric8 Java Base Image (CentOS, OpenJDK 8, … 11 [OK]
blacklabelops/java Java Base Images. 8 [OK]
..............
-
以上表格中五列含义如下:
- NAME:镜像仓库名称
- DESCRIPTION:镜像仓库描述
- STARS:镜像仓库收藏数量,标识该镜像受欢迎程度,类似GitHub的Stars
- OFFICAL:表示是否为官方仓库,改列标记为[OK] 的镜像都是各软件官方项目组创建和维护的。由结果可知,frekele/java 这个镜像不是官方仓库。
- AUTOMATED:表示是否是自动构建的镜像仓库
-
下载镜像
- 使用 docker pull 命令可以从Docker Registry上下载镜像,例如:docker pull java
- 命令执行后,Docker会从Docker Hub上的java残酷中下载最新版本的java镜像。若镜像下载缓慢可以配置加速器(以下会讲解加速器配置)
-
列出已有镜像,使用docker images命令可以列出已经下载的镜像。执行后有如下表格:
REPOSITORY TAG IMAGE ID CREATED SIZE
ubuntu latest adafef2e596e 2 weeks ago 73.9MB
645121107/ljmadmin myHelloWorld bf756fb1ae65 6 months ago 13.3kB
hello-world latest bf756fb1ae65 6 months ago 13.3kB
- 包括五列,分别有如下意义:
- REPOSITORY:镜像所属的仓库名称
- TAG:镜像标签,默认是lastest,表示最新
- IMAGE ID:镜像ID,表示镜像唯一标识
- CREATED:镜像创建时间
- SIZE:镜像大小
- 删除镜像:
docker rmi hello-world
- 删除镜像可能遇到如下问题,原因是提示有关联的Docker容器,因为我们看到bf756fb1ae65 对应了两个容器,一个是我们自己提交的tag,通过hello-world生成的一个镜像,系统无法识别你要删除的是哪一个:
root@ljmadmin-virtual-machine:/home/ljmadmin# docker rmi bf756fb1ae65
Error response from daemon: conflict: unable to delete bf756fb1ae65 (must be forced) - image is referenced in multiple repositories
- 我们删除的时候可以用指定repository和tag的方式来删除,比如:
root@ljmadmin-virtual-machine:/home/ljmadmin# docker rmi hello-world
Untagged: hello-world:latest
Untagged: hello-world@sha256:49a1c8800c94df04e9658809b006fd8a686cab8028d33cfba2cc049724254202
- 如上,线上已经被删除成功
批量删除镜像
- 删除所有:
docker rm `docker ps -a -q`
- 删除所有镜像
docker rmi `docker images -q`
- 按条件删除镜像
//没有标签情况
docker rmi `docker images -q | awk '/^<none>/ {pring $3}'`
//镜像名包含关键字
docker rmi --force `docker images | grep eureka | awk '{print $3}'` //其中eureka为关键字
Docker 容器常用命令
- 新建并启动容器:使用docker run 命令可以新建并启动一个容器。该命令是常用命令,他有很多选项,下面列举某一些选项:
- -d选项:表示后台运行
- -p选项:随机端口映射
- -p选项:指定端扣映射,有以下四种格式:
- ip:hostPort:containerPort
- ip::containerPort
- hostPort:containerPort
- containerPort
- –network选项: 指定网络模式,该选项有以下可选参数:
- –network=bridge:默认选项,表示连接到默认的网桥
- –network=host:容器使用宿主机网络
- –network=container:NAME_or_ID:告诉Docker让新建的容器使用已有容器的网络配置。
- –network=none:不配置该容器网络,用户可以自定义网络配置
- 示例一,这样终端会打印Hello world,跟在本地执行/bin/echo ‘Hello world’ 得到一样的结果:
docker run java /bin/echo 'Hello world'
- 示例二,启动一个Nginx容器,这里添加了两个参数,含义与命令如下所示:
docker run -d -p 91:80 nginx //没有nginx镜像时候,会先下载在启动
// -d 表示后台运行
//-p 宿主机端口:容器端口 # 开放容器端口到宿主机端口
-
访问http://Docker宿主机IP:91,将会看到如下界面
-
进入容器,某些场景下需要进入容器中。
- 使用docker sttach命令进入容器,弊端在于,使用此命令并不方便,当多个窗口同事attach到同一个容器时候,所有窗口都会同步显示。同样,当某个窗口发生阻塞,其他窗口也无法执行操作。命令如下
- 使用nsenter进入容器:nsenter工具包含在util-linux2.23或者更高版本中。为了连接到容器,需要找到容器第一个进程PID,可以以下命令获取
- 以上获取到PID后,就可以使用nsenter进入容器,完整命令如下
docker attach b8488a2dcef8
docker inspect --format "{{.State.Pid}}" $CONTAINER_ID
nsenter --target "$PID" --mount --uts --ipc --net --pid
- 完整案例如下图:
配置镜像加速器
- 国内访问Docker Hub的速度很不稳定,有时候会出现链接不上的情况。我们可以通过配置国内镜像加速器的形式来解决问题。目前,国内很多公司云服务商提供了镜像加速服务。常用镜像加速器有:阿里云加速器,DaoCloud加速器。我用的阿里云的加速器,配置如下:
- 注册阿里云账号,登录控制台(https://cr.console.aliyun.com/cn-hangzhou/instances/mirrors),如下图
- 按上图所示进行配置即可。
使用Docker镜像
- Docker容器是从Docker进行构建的,默认情况下,Docker从Docker Hub中pull下来的这些镜像,这是一个由Docker管理的Docker镜像市场,这是Docker项目背后的公司。任何人都可以在Docker Hub上托管他们的Docker镜像,所以你只要将你的应用程序和LInux放再那边托管就可以。
- 我们用刚才pull的hello-world镜像测试,输入:
docker run hello-world
- 输出下面的内容说明已经成功运行
Hello from Docker!
This message shows that your installation appears to be working correctly.To generate this message, Docker took the following steps:1. The Docker client contacted the Docker daemon.2. The Docker daemon pulled the "hello-world" image from the Docker Hub.(amd64)3. The Docker daemon created a new container from that image which runs theexecutable that produces the output you are currently reading.4. The Docker daemon streamed that output to the Docker client, which sent itto your terminal.
..................
运行Docker容器
- 上一步中,hello-world容器运行并发出一个测试消息后退出容器,容器可以比这更有用,是可以相互交互的,比较,类似虚拟机,只是更加有利于资源。
- 我们用ubuntu的镜像做一个测试,通过-i, -t子命令提供了容器的交互shell访问:
docker pull ubuntu
docker run -it ubuntu
- 执行以上两个命令就可以进入到ubuntu镜像内部,shell展示如下
root@ljmadmin-virtual-machine:/home/ljmadmin# docker run -it ubuntu
root@b8488a2dcef8:/#
- 如上命令提示符中的容器ID,在此处是b8488a2dcef8,在此shell中不需要sudo,因为是用root用户身份在容器中操作,我们在此镜像中安装一个node:
apt update
apt install nodejs
node -v
- 得到如下结果:
root@b8488a2dcef8:/# node -v
v10.19.0
- 退出容器,直接输入exit或者Ctrl+d 退出,两种方式有如下区别
- 对于创建的bash容器,当使用exit命令退出后,容器就自动处于退出(Exited)状态,这是因为对Docker容器来说,当运行的应用退出后,容器就没有继续运行的必要
- 而用Ctrl退出后,容器还会在运行,他认为你只是退出了命令界面的链接状态而已
Docker容器管理
- 使用Docker后,可能有很多非运行状态的容器,我们需要查询容器的运行状态用如下命令:
docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
b8488a2dcef8 ubuntu "/bin/bash" 6 minutes ago Up 6 minutes adoring_knuth
-
看到如上输出,每一列的含义如下:
- CONTAINER_ID:表示容器ID
- IMAGE:表示镜像名称
- COMMAND:表示启动容器时运行的命令
- CREATED:表示容器创建时间
- STATUS:容器运行状态,Up标识运行中,Exited表示停止
- PORTS:容器对外的端口号
- NAMES:表示容器名称,默认由Docker自动生成,也可以docker run 命令后面–name自行指定。
-
查看所有容器情况使用 docker ps -a,得到所有的信息,如下:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
b8488a2dcef8 ubuntu "/bin/bash" 15 minutes ago Up 15 minutes adoring_knuth
43971aec0ea0 hello-world "/hello" 26 minutes ago Exited (0) 26 minutes ago dazzling_hodgkin
- 只查看已经启动的容器:
docker ps
- 启动已经停止的容器,使用Docker start ,后面跟上容器ID b8488a2dcef8 ,启动后status会变为up状态
- 同样,停止容器,使用docker stop CONTAINER_ID,更容器id或者容器名称
- 批量停止容器 docker stop 51c20c4f5a04 22c37049f352 1ac1218c1a54
- 删除容器,当我们不需要某个容器时候,可以docker rm删除,上面内容以及讲过这个命令。
将容器中的更改提交给Docker镜像
- 当启动Docker镜像后,可以像虚拟机一样创建,修改,删除文件。例如ubuntu镜像,我们所有更改都仅仅在镜像内部而已。我们可以通过docker rm销毁,但是会永久丢失。
- 在ubuntu容器中安装Nodejs后,我们现在想要将这个容器作为一个新的容器,可以如下操作:
docker ps -a //找到对应ubuntu镜像id
docker commit -m "my ubuntu" -a "ljmadmin" b8488a2dcef8 ljmadmin/ubuntu-nodejs
- 如上commit命令,对于ljmadmin用户,使用容器id b8488a2dcef8 作为目标镜像,打包成新镜像 ljmadmin/ubuntu-nodejs ,得到如下所有images信息:
root@ljmadmin-virtual-machine:/home/ljmadmin# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
ljmadmin/ubuntu-nodejs latest 6e1bc5c5a996 About a minute ago 163MB
ubuntu latest adafef2e596e 2 weeks ago 73.9MB
645121107/ljmadmin myHelloWorld bf756fb1ae65 6 months ago 13.3kB
hello-world latest bf756fb1ae65 6 months ago 13.3kB
- 在如上列表中新镜像ubuntu-nodejs 是动Docker Hub的Ubuntu现有镜像中衍生出来的,镜像大小的差异可以看出有变化因此下次我们可以直接使用ubuntu-nodejs 新的镜像。
Dockerfile构建镜像
- 待续
将Docker镜像推送到Docker存储库
- 我们以上提到的从Docker Hub pull下来的镜像都是在我们本地,包括我们自己commit生成的也是在本地,如果需要迁移需要先将镜像推到远程仓库,我们需要 一个Docker Hub的仓库账号信息
docker login -u docker-registry-username //docker-registry-username 标识你注册docker Hub的用户名
- 系统将提升输入Docker Hub的密码进行身份验证,然后你可以使用以下方法推送自己的镜像:
- 第一步:获取需要推送到远端镜像的 容器ID(CONTAINER ID),此处我们用ubuntu来进行测试提交,ID是b8488a2dcef8,如下命令:
root@ljmadmin-virtual-machine:/home/ljmadmin# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
b8488a2dcef8 ubuntu "/bin/bash" 3 hours ago Exited (0) 3 hours ago adoring_knuth
43971aec0ea0 hello-world "/hello" 4 hours ago Exited (0) 4 hours ago dazzling_hodgkin
- 第二步将对应Docker容器打包成镜像:
root@ljmadmin-virtual-machine:/home/ljmadmin# docker commit -m "my first ubuntu" -a "ljmadmin" b8488a2dcef8 ljmadmin/ubuntu-nodejs
sha256:acd28a5810ec9e3ecd656fcaf58551552804f7a5663e3c201a1d3d7712621120
- 第三步Docker Images 命令查询打包好的镜像文件,并且获取对应镜像ID:
root@ljmadmin-virtual-machine:/home/ljmadmin# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
ljmadmin/ubuntu-nodejs latest acd28a5810ec 20 seconds ago 163MB
ubuntu latest adafef2e596e 2 weeks ago 73.9MB
hello-world latest bf756fb1ae65 6 months ago 13.3kB
- 第四部:将需要提交的镜像文件通过docker tag命令打包成自己仓库对应的镜像文件(之前的镜像默认是Docker hub公共的仓库)
root@ljmadmin-virtual-machine:/home/ljmadmin# docker tag acd28a5810ec 645121107/ljmadmin
root@ljmadmin-virtual-machine:/home/ljmadmin# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
645121107/ljmadmin latest acd28a5810ec 15 minutes ago 163MB
ljmadmin/ubuntu-nodejs latest acd28a5810ec 15 minutes ago 163MB
ubuntu latest adafef2e596e 2 weeks ago 73.9MB
645121107/ljmadmin myHelloWorld bf756fb1ae65 6 months ago 13.3kB
hello-world latest bf756fb1ae65 6 months ago 13.3kB
- 此处没有指定tag的名称,如需指定名称用以下命令:
docker tag acd28a5810ec 645121107/ljmadmin:yourTagName
-
如上images命令后可以看的多了一个仓库名称(REPOSITORY)是645121107/ljmadmin的镜像文件,并且该镜像文件的id和我们之前通过tag打包成镜像的id是同一个,说明他们是同一个文件,我们可以理解为将他的副本映射到了我们自己的仓库地址,以下是我创建的仓库
-
第五步提交对应镜像文件,通过docker push命令提交
root@ljmadmin-virtual-machine:/home/ljmadmin# docker push 645121107/ljmadmin
- 执行以上命令后会得到如下的输出,因为文件有十几M甚至100M,所以需要一定时间,以上命令和git push类似,645121107/ljmadmin 其实就是远程仓库地址,如果ljmadmin 是别在包例如645121107/1234,docker hub也会自动在远程仓库创建新的文件1234.
- 在仓库中可以看到刚才提交的文件如下:
- 第六部:验证提交的镜像文件有效
docker rmi docker rmi 645121107/ljmadmin:latest //通过rmi命令删除本地对应的镜像文件
root@ljmadmin-virtual-machine:/home/ljmadmin# docker images //查看现有镜像文件
REPOSITORY TAG IMAGE ID CREATED SIZE
ubuntu latest adafef2e596e 2 weeks ago 73.9MB
root@ljmadmin-virtual-machine:/home/ljmadmin# docker pull 645121107/ljmadmin:latest
- 如下图所示,说明以及在下载文件:
查看Docker容器启动日志
- 用的最多的一个,实时日志跟踪,类似 tail -f -n 300 xxx.log
sudo docker logs -f -t --tail 行数 容器名
//docker logs [OPTIONS] CONTAINER
//sudo docker logs -f -t 300 CONTAINER_ID
-
Options操作如下:
- –details 显示更多信息
- -f, --follow 跟踪实时日志信息
- –since string 显示自某个timestamp之后的日志,或相对时间,如40m(40分钟)
- -tail string 从日志末尾开始算显示多少行日志,默认是all
- -t, --timestamp 显示时间搓
- –until string 显示自某个timestamp之前的日志信息,或者相对时间,如40m(40分钟)
-
查看最近30分钟的日志:
docker logs --since 30m CONTAINER_ID
- 查看某时间之后的日志:
docker logs -f --since = "2020-08-26T13:23:37" CONTAINER_ID
- 查看某时间段日志:
docker logs -t --since= "2020-08-25T13:23:37" --until "2020-08-26T13:23:37" CONTAINER_ID
下一篇 SpringCloud + Docker