Docker学习笔记

244 阅读5分钟

「这是我参与2022首次更文挑战的第16天,活动详情查看:2022首次更文挑战」。

前言

本文为我之前在CSDN平台上的一篇博客记录。原链接为:Docker学习笔记

导语

学习需要,最近要简要了解一下docker相关技术,特此记录如下。学习内容为慕课网免费课《docker入门》

1 Docker介绍

Docker是一种容器技术,容器技术本质上就是将程序打包的一个过程。他并不是一个很新的技术,核心技术在内核里已经存在很久了。Docker解决了软件包装的问题,很好的理顺了运维和开发的差异,使得开发和运维可以用同一语言来沟通。

那么什么是Docker呢?我们看一下官方的定义: 在这里插入图片描述 官方说Docker是一个开源的项目,他可以用来将任何应用以轻量级容器的形式进行打包、发布和运行。Node.js说Docker允许一个应用程序及其所有依赖以一种标准的单位来打包。这两个概念都比较抽象,我们来做一个简单的类比。

首先,docker可以被粗糙的理解为轻量级的虚拟机。它和虚拟机完成相似的任务,即把一个应用程序放到一个独立的环境里允许。但docker的确不是虚拟机

在这里插入图片描述 如图所示,虚拟机在宿主OS上有一层虚拟层Hypervisor。在其上我们会安装各种独立的guest OS然后在运行各种软件。Docker是不一样的,它是有一层Docker engine层,在之上运行各种各样的应用程序。他没有虚拟层这一层,所以会比虚拟机轻量级很多。其他的包括程序启动速度、内存需求都会好很多。

2 下载与安装

这里展示在Linux下安装docker。首先,需要使用以下命令来安装docker

sudo wget -qO- https://get.docker.com/ | sh
sudo usermod -aG docker test_user

第一条命令用于下载安装docker,第二条命令用于给非root用户test_user操作docker的权限。在跟着视频配置时,出现了报错“Got permission denied while trying to connect to the Docker daemon socket”,解决方法参考:解决Ubuntu18.04启动Docker“Got permission denied while trying to connect to the Docker daemon socket“问题

之后,输入

docker info

就可以看到返回信息

jxqi@ubuntu:~$ docker info
Client:
 Context:    default
 Debug Mode: false
 Plugins:
  app: Docker App (Docker Inc., v0.9.1-beta3)
  buildx: Build with BuildKit (Docker Inc., v0.6.1-docker)
  scan: Docker Scan (Docker Inc., v0.8.0)

Server:
 Containers: 2
  Running: 0
  Paused: 0
  Stopped: 2
 Images: 1
 Server Version: 20.10.8
 Storage Driver: overlay2
  Backing Filesystem: extfs
  Supports d_type: true
  Native Overlay Diff: true
  userxattr: false
 Logging Driver: json-file
 Cgroup Driver: cgroupfs
 Cgroup Version: 1
 Plugins:
  Volume: local
  Network: bridge host ipvlan macvlan null overlay
  Log: awslogs fluentd gcplogs gelf journald json-file local logentries splunk syslog
 Swarm: inactive
 Runtimes: io.containerd.runc.v2 io.containerd.runtime.v1.linux runc
 Default Runtime: runc
 Init Binary: docker-init
 containerd version: e25210fe30a0a703442421b0f60afac609f950a3
 runc version: v1.0.1-0-g4144b63
 init version: de40ad0
 Security Options:
  apparmor
  seccomp
   Profile: default
 Kernel Version: 5.4.0-81-generic
 Operating System: Ubuntu 18.04.5 LTS
 OSType: linux
 Architecture: x86_64
 CPUs: 2
 Total Memory: 3.816GiB
 Name: ubuntu
 ID: NXOJ:ARLU:QYED:RHOH:XDFF:JL3C:4VFD:N22F:45EF:2GQQ:3LB3:QKTC
 Docker Root Dir: /var/lib/docker
 Debug Mode: false
 Registry: https://index.docker.io/v1/
 Labels:
 Experimental: false
 Insecure Registries:
  127.0.0.0/8
 Live Restore Enabled: false

WARNING: No swap limit support

3 Docker架构与常用命令

3.1 Docker架构

在这里插入图片描述 Docker架构如图所示,中间是host,也就是进行docker操作的宿主机。宿主机上运行一个叫docker daemon的核心程序,这个程序负责做各种各样的操作,比如下载docker镜像、运行一个容器等。我们通过客户端和docker daemon用命令进行交互,比如build、run等,通过这些命令由docker daemon来做实际的操作。右边蓝色的是一个互联网SaaS服务,daemon可以与之交互来获取一些镜像,他其实是所有docker用户共享docker镜像的一个服务。

在这里插入图片描述

3.2 Docker常用命令

docker常用命令总结如下:

命令说明示例
docker run image_name运行一个containerdocker run ubuntu echo hello docker
docker stop container_id停止一个containerdocker stop df45e4f54ef8
docker commit -m '容器提交的msg' 容器ID 生成新镜像名字提交修改后的新的imagedocker commit -m 'add new function' test0827
docker ps [-a]列出当前运行的容器(-a列出所有容器)docker ps -a
docker images列出所有imagedocker images
docker rm container_id1, container_id2, ……删除容器docker rm 1df548rgfh4y, f45rrdg591vb
docker rmi image_id1, image_id2, ……删除镜像docker rmi -f runoob/ubuntu:v4
docker pull从远端服务获取imagedocker pull java
docker build创建imagedocker build -t runoob/ubuntu:v1
docker cp在host和container之间拷贝文件docker cp 文件名 容器ID://usr/share/nginx/html

3.3 Docker中容器和镜像的区别

一个通俗易懂的解释是镜像就是一个抽象的类定义,而容器则是该类的一个实例化。也就是说,一个镜像可以有多个容器运行,镜像只是一个定义好的软件和环境集合。

4 Dockerfile

4.1 Dockerfile介绍

我们可以通过编写简单的文件自创docker镜像。我们以一个简单的Dockerfile示例展开:

FROM alpine:latest
MAINTAINER jxqi
CMD echo "Hello Docker!"

上面是一个简单的Dockerfile。我们逐行解释: 第一行FROM alpline:latest意味着我们要产生一个新镜像,它的base镜像是什么(可以将其类比为定义新类时的基础类),alpine是专门为docker设计的一个非常小的Linux系统。 第二行MAINTAINER jxqi并没有什么意义,只是在共享时告诉其他人,这个是jxqi写的。 第三行运行一个命令,这个命令就是echo "Hello Docker!"

接下来我们来实验一下,首先创建一个Dockerfile文件,文件名称就叫Dockerfile(约定俗成)。将内容写入后我们使用build命令来构建新的image。

docker build -t hello_docker .

-t就是给它一个标签叫hello_docker,这里的.代表了当前文件路径,事实上是把这个路径里的所有文件都送给docker engine让它来产生image。相关命令和输出如下:

jxqi@ubuntu:~/docker_laern$ cat Dockerfile 
FROM alpine:latest
MAINTAINER jxqi
CMD echo "Hello Docker!"
jxqi@ubuntu:~/docker_laern$ docker build -t hello_docker .
Sending build context to Docker daemon  2.048kB
Step 1/3 : FROM alpine:latest
latest: Pulling from library/alpine
a0d0a0d46f8b: Pull complete 
Digest: sha256:e1c082e3d3c45cccac829840a25941e679c25d438cc8412c2fa221cf1a824e6a
Status: Downloaded newer image for alpine:latest
 ---> 14119a10abf4
Step 2/3 : MAINTAINER jxqi
 ---> Running in 57449629e6fd
Removing intermediate container 57449629e6fd
 ---> 8e8b54f1e591
Step 3/3 : CMD echo "Hello Docker!"
 ---> Running in bac677a517ed
Removing intermediate container bac677a517ed
 ---> 1d002e696880
Successfully built 1d002e696880
Successfully tagged hello_docker:latest
jxqi@ubuntu:~/docker_laern$ docker images
REPOSITORY     TAG       IMAGE ID       CREATED          SIZE
hello_docker   latest    1d002e696880   24 seconds ago   5.6MB
alpine         latest    14119a10abf4   15 hours ago     5.6MB
ubuntu         latest    1318b700e415   4 weeks ago      72.8MB

我们通过docker images也可以看到新生成的hello_docker,它被自动打了标签TAG为latest。运行如下:

jxqi@ubuntu:~/docker_laern$ docker run hello_docker
Hello Docker!

4.2 Dockerfile实战

我们来看一个相对复杂的Dockerfile。其内容如下:

FROM ubuntu
MAINTAINER me@hazyzh.com
RUN sed -i 's/archive.ubuntu.com/mirrors.ustc.edu.cn/g' /etc/apt/sources.list
RUN apt-get update
RUN apt-get install -y nginx
COPY index.html /var/www/html
ENTRYPOINT ["usr/sbin/nginx", "-g", "daemon off;"]
EXPOSE 80

这里我们启动了一个Nginx服务,并将其端口80暴露出来。整体docker是在Ubuntu上改写的。这里我也在该目录下准备一个index.html的文件用于拷贝。然后我们执行,可以在浏览器访问到这个index.html。相关代码如下:

jxqi@ubuntu:~/docker_laern/docker_file2$ docker run -d -p 80:80 hello-nginx 
d564e698c89b0be92aa837bb078e80435fb85dfa185976b10b1141e8702c6e38
jxqi@ubuntu:~/docker_laern/docker_file2$ curl http://localhost
<!DOCCTYPE html>
<html>
<head>
Hello world.   
</head>
<body>
好好学习,天天向上!
</body>
<html>

在这里插入图片描述 这里乱码是中文。

4.3 Dockerfile语法小结

在这里插入图片描述

在这里插入图片描述

详细语法可参考Dockerfile语法简介

5 镜像分层

Docker中一个重要的概念是镜像被分层存储,而不是作为一个整个的文件被存储。Dockerfile里每一行都会产生一个新层。 在这里插入图片描述 在image里的几个层都是只读的。如下图中的下面三个层都是只读的。一旦一个image被运行产生一个容器,那么会产生一个新层container层。这一层是可读可写的,保证我们的容器是可以被改变的。 在这里插入图片描述 那么分层有什么好处呢?答案是减轻存储压力,比如一个image有7层,一个有10层,但它们有5层都是相同的,这些共用的层只要存储一次就可以了。

6 Volume

6.1 Volume简介

Volume是docker的一个存储技术,它提供独立于容器之外的持久化存储。之前我们在容器中的操作是默认不会被保存的。但有些场景下,比如我们运行了一个数据库容器,数据库中的数据应当是被持久化的,Volume就可以做这个事情。并且,Volume可以提供给容器之间共享的数据。

6.2 Volume操作

6.2.1 挂起一个数据卷

我们看一个最简单的示例,使用docker运行一个Nginx容器,然后挂载一个卷。

以下命令中-v表示挂起一个卷,-d表示以守护进程来运行,--name给一个名字,这里也叫ngin。

docker run -d --name nginx -v /usr/share/nginx/html/ nginx

然后使用命令检测容器的运行状态

docker inspect nginx

得到输出如下:

jxqi@ubuntu:~/docker_laern/docker_file2$ docker run -d --name nginx -v /usr/share/nginx/html/ nginx
d7ef0ef7ff209deb15eb8c021924bf93460854c0fa7e91719a8dca51e307a997
jxqi@ubuntu:~/docker_laern/docker_file2$ docker inspect nginx
[
    {
        "Id": "d7ef0ef7ff209deb15eb8c021924bf93460854c0fa7e91719a8dca51e307a997",
        "Created": "2021-08-29T01:38:01.363321297Z",
        "Path": "/docker-entrypoint.sh",
        "Args": [
            "nginx",
            "-g",
            "daemon off;"
//
// 输出太长了,省略一部分内容
//
        "Mounts": [
            {
                "Type": "volume",
                "Name": "0e7a7f84d746a7f6a01552cf5295bfe9a94c73c8ff713e1c64fa18b7d565ff4f",
                "Source": "/var/lib/docker/volumes/0e7a7f84d746a7f6a01552cf5295bfe9a94c73c8ff713e1c64fa18b7d565ff4f/_data",
                "Destination": "/usr/share/nginx/html",
                "Driver": "local",
                "Mode": "",
                "RW": true,
                "Propagation": ""
            }
        ],
//
// 输出太长了,省略一部分
//

可以看到挂载的容器目标地址为Source字段的"/var/lib/docker/volumes/0e7a7f84d746a7f6a01552cf5295bfe9a94c73c8ff713e1c64fa18b7d565ff4f/_data"。查看与修改该文件,使用如下命令:

jxqi@ubuntu:~/docker_laern/docker_file2$ cd /var/lib/docker/volumes/0e7a7f84d746a7f6a01552cf5295bfe9a94c73c8ff713e1c64fa18b7d565ff4f/_data
jxqi@ubuntu:/var/lib/docker/volumes/0e7a7f84d746a7f6a01552cf5295bfe9a94c73c8ff713e1c64fa18b7d565ff4f/_data$ ls
50x.html  index.html
jxqi@ubuntu:/var/lib/docker/volumes/0e7a7f84d746a7f6a01552cf5295bfe9a94c73c8ff713e1c64fa18b7d565ff4f/_data$ su 
Password: 
root@ubuntu:/var/lib/docker/volumes/0e7a7f84d746a7f6a01552cf5295bfe9a94c73c8ff713e1c64fa18b7d565ff4f/_data# echo "it's 2021." > index.html

这里,我们使用echo命令将一段字符串写入到了index.html文件中。我们进入到nginx容器中,查看是否被修改,并通过curl命令检查。

root@ubuntu:/var/lib/docker/volumes/0e7a7f84d746a7f6a01552cf5295bfe9a94c73c8ff713e1c64fa18b7d565ff4f/_data# docker exec -it nginx /bin/bash
root@d7ef0ef7ff20:/# cd /usr/share/nginx/html/
root@d7ef0ef7ff20:/usr/share/nginx/html# ls
50x.html  index.html
root@d7ef0ef7ff20:/usr/share/nginx/html# cat index.html 
it's 2021.
root@d7ef0ef7ff20:/usr/share/nginx/html# curl http://localhost
it's 2021.

可以看到,内容已经被修改完毕。

6.2.2 将本地目录挂载到容器中的数据卷

首先,我们在当前目录下新建一个目录html,并在里面新建一个index.html文件,内容如下:

<html>
	<h1>Hello docker</h1>
</html>

然后使用如下命令,将当前目录下的html挂载到nginx容器中:

docker run -p 80:80 -d -v $PWD/html:/usr/share/nginx/html nginx

通过访问浏览器可以看到 在这里插入图片描述 我们接下来修改index.html的内容:

<html>
	1+1=2
</html>

刷新网页,可以看到页面被修改了 在这里插入图片描述

6.2.3 创建一个仅提供数据的容器,把这个容器当做volume挂载到其它容器

我们首先创建一个数据容器

jxqi@ubuntu:~/docker_laern$ mkdir vol3
jxqi@ubuntu:~/docker_laern$ cd vol3
jxqi@ubuntu:~/docker_laern/vol3$ mkdir data
jxqi@ubuntu:~/docker_laern/vol3$ docker create -v $PWD/data:/var/mydata --name data_container ubuntu
9a421840833b040704d4c130c43a30b82805048973d675915c8294281482bb32

其中,-v 表示的是volume(数据卷) --name 名字 ubuntu 是这个容器的基础镜像。然后,我们运行一个新的容器,把上面提供数据的容器当做数据卷挂载到当前的容器中运行,-it表示交互的方式运行,会直接进入到这个容器中。

jxqi@ubuntu:~/docker_laern/vol3$ docker run -it --volumes-from data_container ubuntu /bin/bash
root@82c6c2151eae:/# ls
bin  boot  dev  etc  home  lib  lib32  lib64  libx32  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var
root@82c6c2151eae:/# cd var/mydata/
root@82c6c2151eae:/var/mydata# ls
root@82c6c2151eae:/var/mydata# touch newfile.txt
root@82c6c2151eae:/var/mydata# ls
newfile.txt

退出当前容器,我们查看data文件夹下的情况

root@82c6c2151eae:/var/mydata# exit
exit
jxqi@ubuntu:~/docker_laern/vol3$ ls
data 
jxqi@ubuntu:~/docker_laern/vol3$ cd data/
jxqi@ubuntu:~/docker_laern/vol3/data$ ls
newfile.txt

可以看到,data目录下多了一个newfile.txt的文件,说明了 data_container 这个容器被当做了数据卷,它也可以被多个容器共享。

7 Registry

docker中的Registry又叫做镜像仓库,可以供大家共享镜像。我们可以与Registry通过命令进行交互。

7.1 使用Registry上的镜像

以下我们来实际演示以下,首先我们可以在Registry上搜索一个镜像,

docker search whalesay

whalesay没有实际意义,只是提供了在命令行画鲸鱼的作用。搜索结果如下:

jxqi@ubuntu:~/docker_laern/vol3/data$ docker search whalesay
NAME                           DESCRIPTION                                     STARS     OFFICIAL   AUTOMATED
docker/whalesay                An image for use in the Docker demo tutorial    701                  
swinton/whalesay               whalesay, innit                                 1                    
nikovirtala/whalesay           Tiny Go web service to print Moby Dock ASCII…   1                    [OK]
ojenge/whalesay                from docker/whalesay                            1                    
milanfort/whalesay             Modified docker/whalesay image that outputs …   1                    
sabs1117/whalesay              Whalesay with fortune phrases.                  1                    
caibar/whalesay                Builds automatizados.                           1                    [OK]
getporter/whalesay                                                             0                    
whalebrew/whalesay                                                             0                    
blaines/whalesay                                                               0                    
yang225217/whalesay                                                            0                    
dhalljohnston/whalesay         whalesay                                        0                    
gapfish/whalesay-ruby          whalesay function test                          0                    
forsingh/whalesay              whalesay                                        0                    [OK]
nikovirtala/whalesay-win       Whalesay running on Microsoft IIS on Nano Se…   0                    [OK]
getporter/whalesay-installer                                                   0                    
carolynvs/whalesayd                                                            0                    
hongxi/whalesay-fortunes       Demo, the whalesay-fortunes                     0                    
maghnus/whalesayentrypoint     I need a version of whalesay with entrypoint…   0                    
ox0spy/whalesay-fortune        like docker/whalesay, just using fortunes pr…   0                    
phyominhtun/whalesay           WhaleSay Container                              0                    
burleyinnersbm07/whalesay      Edit to the WhaleSay                            0                    
dockeramiller/whalesay         Modified version of the official docker/whal…   0                    [OK]
ok7827125/whalesay                                                             0                    
jenniferw/whalesay-tutorial    tutorial for whalesay 2.0                       0                    

我们选择第一个镜像把他下载到本地

docker pull docker/whalesay

下载完成后,我们可以运行这个镜像

docker run docker/whalesay cowsay "Hello docker"

运行效果如下: 在这里插入图片描述

7.2 上传自己的镜像到docker hub

在此之前要有一个docker hub的账号,可以在官网注册。上传镜像时,要先在终端中登录这个账号。这里,我们演示将下载下来的image改成我们的image然后上传(仅供学习)。

首先,我们将下载的docker镜像改一个自己的名字:

jxqi@ubuntu:~/docker_laern/vol3/data$ docker tag docker/whalesay:latest jxqi/whalesay:leatest
jxqi@ubuntu:~/docker_laern/vol3/data$ docker images
REPOSITORY        TAG       IMAGE ID       CREATED        SIZE
hello-nginx       latest    4a6091bd6338   41 hours ago   162MB
hello_docker      latest    1d002e696880   41 hours ago   5.6MB
alpine            latest    14119a10abf4   2 days ago     5.6MB
nginx             latest    dd34e67e3371   12 days ago    133MB
ubuntu            latest    1318b700e415   4 weeks ago    72.8MB
docker/whalesay   latest    6b362a9f73eb   6 years ago    247MB
jxqi/whalesay     leatest   6b362a9f73eb   6 years ago    247MB

接着,登录docker

jxqi@ubuntu:~/docker_laern/vol3/data$ docker login
Login with your Docker ID to push and pull images from Docker Hub. If you don't have a Docker ID, head over to https://hub.docker.com to create one.
Username: jxqi
Password: 
WARNING! Your password will be stored unencrypted in /home/jxqi/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store

Login Succeeded

然后,使用docker push命令上传。

jxqi@ubuntu:~/docker_laern/vol3/data$ docker push jxqi/whalesay:leatest 
The push refers to repository [docker.io/jxqi/whalesay]
5f70bf18a086: Mounted from docker/whalesay 
d061ee1340ec: Mounted from docker/whalesay 
d511ed9e12e1: Mounted from docker/whalesay 
091abc5148e4: Mounted from docker/whalesay 
b26122d57afa: Mounted from docker/whalesay 
37ee47034d9b: Mounted from docker/whalesay 
528c8710fd95: Mounted from docker/whalesay 
1154ba695078: Mounted from docker/whalesay 
leatest: digest: sha256:4a79736c5f63638261bc21228b48e9991340ca6d977b73de3598be20606e5d87 size: 2402

8 多容器应用

我们通过docker-compose工具实现,在Mac/Windows下自带,Linux下使用这个命令安装

curl -L https://get.daocloud.io/docker/compose/releases/download/1.29.2/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose

这里我们切换了阿里云镜像来加速下载。

使用

chmod a+x /usr/local/bin/docker-compose 

将docker-compose变为所有用户可用。完成后检查版本已验证命令是否可用。

jxqi@ubuntu:~/docker_laern/vol3/data$ sudo chmod a+x /usr/local/bin/docker-compose 
jxqi@ubuntu:~/docker_laern/vol3/data$ docker-compose --version
docker-compose version 1.29.2, build 5becea4c

======================================================================

还差一点内容,后续有时间补上

======================================================================