Docker学习笔记——Docker基础
Docker 是一个开源的应用容器引擎,基于 Go 语言 并遵从 Apache2.0 协议开源。Docker 可以让开发者打包他们的应用以及依赖包到一个轻量级、可移植的容器中,然后发布到任何流行的 Linux 机器上,也可以实现虚拟化。容器是完全使用沙箱机制,相互之间不会有任何接口(类似 iPhone 的 app),更重要的是容器性能开销极低。Docker的构想是要实现“Build, Shi
一、Dokcer简介
官方介绍:
Docker 是一个开源的应用容器引擎,基于Go 语言并遵从 Apache2.0 协议开源。
Docker 可以让开发者打包他们的应用以及依赖包到一个轻量级、可移植的容器中,然后发布到任何流行的 Linux 机器上,也可以实现虚拟化。
容器是完全使用沙箱机制,相互之间不会有任何接口(类似 iPhone 的 app),更重要的是容器性能开销极低。
Docker的构想是要实现“Build, Ship and Run Any App, Anywhere”,即通过对应用的封装(Packaging)、分发(Distribution)、部署(Deployment)、运行生命周期(Runtime)进行管理,达到应用组件级别的“一次封装,到处运行”。
本人理解:
我们在开发到上线一个程序的时候需要接触很多环境,比如:开发环境(一般是在自己电脑)、测试环境、生产环境,在不同的环境中我们开发出的程序可能出现一些问题。可能在自己电脑上可以跑的程序,到了其它机器上就会因为环境不同而出现一些问题。而且换到不同的机器上我们就需要重新配置环境。例如下图所示。所以我们就想,如果能把环境一起打包运行,那样不就可以解决不同运行环境的问题了。使用Docker就可以解决这样的问题,我们可以使用Docker将程序以及环境打包为一个镜像,并上传到远程仓库,当需要在其它机器上运行时,只需要将镜像从远程仓库拉取下来直接运行即可。
Docker是一个C/S架构的软件,Docker会启动一个守护进程用来接收客户端的命令并执行相应的命令。比如:docker run 镜像名,可以根据一个镜像运行一个容器。
1、Docker中的名词概念
镜像(Image):
Docker中的镜像就像是一个只读的模板,比如操作系统镜像,我们可以使用操作系统镜像来安装一个操作系统;又像是面向对象中的类,通过类我们可以创建一个对象。镜像是可以复用的,我们可以通过Docker运行一个镜像实例,运行起来的镜像就是一个容器。
容器(Container):
Docker容器类似一个轻量级的沙箱,Docker利用容器技术来运行和隔离应用。容器是从镜像创建的应用运行实例。它可以启动、开始、停止、删除,而这些容器都是彼此相互隔离、互不可见的。
可以把容器看作一个简易版的Linux系统环境(包括root用户权限、进程空间、用户空间和网络等)以及运行在其中的应用程序打包而成的盒子。
仓库(Repository)
Docker仓库类似代码仓库,是Docker集中存放镜像文件的仓库,仓库分为私有仓库和公有仓库。可以通过Docker从仓库中拉取一个镜像,也可以上传自己的镜像。目前最大的公开仓库是官方提供的Docker Hub,就像Github一样,Docker Hub存放了很多官方的或者非官方的镜像,例如:nginx镜像、redis镜像等。官网:https://hub.docker.com/
如下图,下图中包含了三部分,分别时Docker客户端、Docker守护进程以及远程仓库。Docker客户端可以接收命令并通知Docker守护进程来进行一系列的操作,比如拉取镜像、运行容器等。Docker守护进程将会管理镜像以及容器。远程仓库存放了很多种不同的镜像。
Docker的安装:Ubuntu20.04安装Docker_Peerless__的博客-CSDN博客
二、Docker基本使用
在使用下面的命令时,可以加参数 --help 来查看帮助文档。例如dokcer run --help:
下面显示了docker run命令的使用方式以及其它的可选参数和其解释。
1、镜像
1.1 查看镜像
docker images
使用docker images命令可以查看本机已经存在的镜像。分别显示了镜像名、标签(版本信息)、镜像ID、创建时间以及镜像的大小。
除此之外,还有一些可选参数,可以通过docker images --help 命令来查看,下面两个是比较常用的参数:
# -a参数,显示所有的镜像 docker images -a
-a, --all Show all images (default hides intermediate images)
# -q参数,只显示镜像ID
-q, --quiet Only show image IDs
1.2 给镜像设置标签
docker tag sourname:tag desname:tag
#例如:
docker tag ubuntu:18.04 myubuntu:lastest
1.3 搜索镜像
docker search 镜像名
#参数:
# 过滤输出内容
-f, --filter filter Filter output based on conditions provided
# 限制输出个数
--limit int Max number of search results (default 25)
# 例如
docker search --filter=is-official=true mysql # 搜索mysql官方镜像
docker search --filter=stars=200 mysql # 搜索star大于200的mysql镜像
docker search --limit 5 mysql # 只显示5个输出
使用docker search可以从远程仓库搜索镜像,上面显示了镜像名、描述、stars、是否是官方镜像等信息。
1.4 拉取镜像
docker pull 镜像名
docker pull 镜像名:tag
#例如
docker pull mysql # 不加tag,将会拉取最新版本
docker pull mysql:5.7 # 拉取5.7版本的mysql
在镜像名后可以指定拉取的版本,如果不指定就会拉取最新版本,关于镜像的版本可以到docker hup来搜索。网址:https://hub.docker.com/
1.5 删除镜像
使用下面命令可以删除本机仓库中的一个镜像,rmi ==> remove image
docker rmi 镜像名 或 镜像ID
#例如 docker rmi centos 或 docker rmi 9f266d35e02c , 命令Docker images可以查看镜像ID
参数:
# 强制删除,类似linux命令 rm -f
-f, --force Force removal of the image
# 如果要删除所有的镜像可以使用以下命令, docker images -aq 会显示所有镜像的ID
docker rmi `docker images -aq` 或
docker rmi $(docker images -aq)
1.6 导出和载入镜像
Docker镜像的save和load命令可以将镜像导出到本地以及加载本地镜像到镜像库。使用save命令可以将镜像导出到本地,这样就可以跟别人分享自己的镜像,当然也可以提交到远程仓库,将在后面介绍。通过load命令则可以加载别人分享的镜像。
docker save -o 生成的镜像名 镜像
# 例如
docker save -o mysql5_7.tar mysql:5.7
docker load -i 本地镜像名 或者
docker load < 本地镜像名
2、容器
2.1 运行容器
docker run 镜像名
参数:
-d, --detach Run container in background and print container ID 后台运行容器
-e, --env list Set environment variables 设置环境变量
--expose list Expose a port or a range of ports 暴露端口
-i, --interactive Keep STDIN open even if not attached 交互模式
--name string Assign a name to the container 给当前运行的容器指定名字
-p, --publish list Publish a container's port(s) to the host 指定端口映射
-P, --publish-all Publish all exposed ports to random ports 随机指定暴露的端口映射
-t, --tty Allocate a pseudo-TTY 分配一个终端
-v, --volume list Bind mount a volume 挂载数据卷
--volumes-from list Mount volumes from the specified container(s) 从一个数据卷容器挂载目录
-w, --workdir string Working directory inside the container 指定容器中的工作目录
我们可以使用交互模式来运行一个容器,例如下面命令:
docker run -it --name c1 centos /bin/bash
-t选项让Docker分配一个伪终端并绑定到容器的标准输入上,-i则让容器的标准输入保持打开,–name给容器指定名字,centos为创建容器使用的镜像,/bin/bash为容器中运行的终端。如果镜像不存在,Docker会从远程仓库拉取,然后再运行。如下图,运行容器后发现终端发生了变化,说明我们已经进入了容器,用户为root用户,@后的一串字符为当前容器的ID。可以使用ls命令来查看当前目录下的文件。
输入exit命令可以退出当前容器。
使用docker ps -a来查看所有容器,发现刚刚运行的容器在退出后就停止运行了。对于所创建的bash容器,当用户使用exit命令退出bash进程后,容器也会自动退出。这是因为对于容器来说,当其中的应用退出后,容器的使命完成,也就没有运行的必要了。
使用 Ctrl + p + q来退出容器可以让容器在后台继续运行。
我们可以在启动时让容器在后台运行,这样在退出容器后,容器会继续运行。
docker run -id --name c2 centos
运行后,输出了运行的容器的ID。使用docker ps -a命令来查看所有容器,发现刚刚启动的容器还在运行
可以使用下面的命令进入容器:
docker exec -it c2 /bin/bash 或
docker exec -it 29f35e8928c5 /bin/bash
在进入容器并退出后发现,c2容器依然在运行。
当利用docker run来创建并启动容器时,docker在后台运行的标准操作包括:
- 检查本地是否存在指定的镜像,不存在就从远程仓库下载;
- 利用镜像创建一个容器,并启动该容器;
- 分配一个文件系统给容器,并在只读的镜像层外面挂载一层可读写层;
- 从宿主主机配置的网桥接口中桥接一个虚拟接口到容器中去;
- 从网桥的地址池配置一个IP地址给容器;
- 执行用户指定的应用程序;
- 执行完毕后容器被自动终止。
2.2 查看容器
docker ps
参数:
# 查看所有容器
-a, --all Show all containers (default shows just running)
# 只显示容器ID
-q, --quiet Only display container IDs
使用docker ps可以查看容器,类似linux的ps命令查看进程。不加参数只会显示当前正在运行的容器,-a参数可以显示所有容器,-q只显示容器ID,如果要删除所有容器就可以使用该参数了,类似删除全部镜像。
2.3 停止容器
1)暂停容器
# 暂停容器
docker pause 容器名 或 ID
# 继续运行暂停的容器
docker unpause 容器名 或 ID
2)终止容器
docker stop 容器名 或 ID
该命令会首先向容器发送SIGTERM信号,等待一段超时时间后(默认为10s),再发送SIGKILL信号来终止容器。
2.4 启动容器
docker start 容器名 或 ID
# 重启容器,先终止再启动
docker restart 容器名 或 ID
2.5 删除容器
docker rm 容器名 或 ID
参数:
#强制删除容器
-f, --force Force the removal of a running container (uses SIGKILL)
容器在运行时使用docker rm无法删除,需要加-f参数才可。
如果要删除所有容器,也可以使用类似删除所有镜像的命令:
docker rm `docker ps -aq` 或
docker rm $(docker ps -aq)
2.6 导入和导出容器
某些时候,需要将容器从一个系统迁移到另外一个系统,此时可以使用Docker的导入和导出功能。
1)导出容器
导出容器是指,导出一个已经创建的容器到另一个文件,不管这个容器是否处于运行状态。
docker export -o exportname 容器名 或
docker export 容器名 > exportname
# 例如
docker export -o test_for_run.tar ce1
docker export ce1 > test_for_run
之后,可将导出的tar文件传输到其它机器上,然后通过导入命令导入到系统中,实现容器的迁移。
2)导入容器
docker import filename
2.7 查看容器的相关信息
使用docker inspect可以查看容器的具体信息,会以json格式返回容器ID、创建时间、路径、状态、镜像、配置在内的各项信息。
docker inspect 容器名 或 ID
# 同样使用docker inspect 镜像名 或 镜像ID 也可以查看镜像的相关信息
里面有很多参数,在这里只展示了一部分。
使用下面的命令可以查看docker容器中的进程信息。
docker top 容器名 或 ID
2.8 运行容器时的其它参数
设置环境变量
-e, --env list Set environment variables 设置环境变量
使用-e命令可以给运行的容器设置环境变量
暴露端口
--expose list Expose a port or a range of ports 暴露端口
例如,运行nginx时可以将容器的80端口进行暴露。
端口映射
我们在外部机器是无法直接通过网络与容器进行通信的,但是宿主机是可以和容器直接通信的,因此我们可以借助宿主机来和容器进行通信。
例如下图,在容器中运行了一个端口为3306的mysql数据库,在外部机器中是无法直接访问容器中的mysql的。因此可以配置一个端口映射,容器中的3306端口映射到宿主机的3307端口(也可以是其它端口),这样我们可以直接通过宿主机的IP以及端口来访问容器中的数据库。
-p, --publish list Publish a container's port(s) to the host 指定端口映射
-P, --publish-all Publish all exposed ports to random ports 随机指定暴露的端口映射
例如在运行nginx时,可以将容器内的80端口映射为宿主机的8080端口,我们就可以在浏览器中通过8080端口来访问容器中的nginx。-p自己指定映射的端口。
-P让docker来随机指定映射的端口。
可以使用docker inspect来查看映射的端口:
指定工作目录
-w, --workdir string Working directory inside the container 指定容器中的工作目录
可以通过-w命令来指定容器中的工作目录,运行容器后,容器就在指定的工作目录。
2.9 数据管理
在生产环境中使用Docker,往往需要对数据进行持久化,或者需要在多个容器直接进行数据共享,这必然涉及容器的数据管理操作,容器中的管理数据主要有两种方式:
- 数据卷(Data Volumes):容器内数据直接映射到本地主机环境;
- 数据卷容器(Data Volume Containers):使用特定容器维护数据卷。
挂载数据卷
数据卷是一个可供容器使用的特殊目录,它将主机操作系统目录直接映射进容器,类似Linux中的mount行为。
数据卷可以提供很多有用的特性:
- 数据卷可以在容器间共享和重用,容器间传递数据将变得高效与方便;
- 对数据卷内数据的修改会立马生效,无论是容器内操作还是本地操作;
- 对数据卷的更新不会影响镜像,解耦开应用和数据;
- 卷会一直存在,直到没有容器使用,可以安全地卸载它(即使容器被删除了,本地数据卷也不会被删除)。
-v, --volume list Bind mount a volume 挂载数据卷
# 使用: -v 宿主机目录:容器目录
当容器在删除后,容器中的数据也就随之被删除了。如果我们运行了一个mysql的容器,当容器被删除后,我们不希望mysql中的数据也被删除。因此我们可以将容器中的数据与宿主机的一个目录建立一个映射,这两个目录中的数据会被同步。
如上图所示,运行了一个名字为c6的centos的容器,并指定了宿主机的/home/mgh/data与容器/usr/local/data的映射(如果路径中的文件夹不存在,则会创建),在容器的/usr/local/data目录中创建了hello.txt并写入内容。然后退出容器,在宿主机的/home/mgh/data目录中发现也有这样一个文件。同时在宿主机中创建了world.txt文件,进入容器后也可以看到该文件。
我们也可以将多个容器中的一个目录挂载在宿主机的同一个目录下,这样就可以在容器间共享数据了。
数据卷容器
多个容器共享数据,我们可以将它们挂载在同一个目录,如果创建比较多的容器的话,这种方式操作还是比较麻烦的。另一种方法就是创建一个数据卷容器,在运行这个容器时将目录挂载在宿主机上,在启动其它容器时我们可以使用–volumes-from并指定数据卷容器来共享数据。
--volumes-from list Mount volumes from the specified container(s) 从一个特殊的容器中挂载数据卷
# 例如 也可以指定多个目录
docker run -id --name volume-container -v /home/data:/usr/local/data centos
docker run -id --name volume-des1 --volumes-from volume-container centos
如上图所示,先使用命令创建了一个数据卷容器,将容器中/usr/local/data挂载到宿主机的/home/data中,然后创建了三个容器并指定了数据卷容器。可以看到在数据卷容器的/usr/local/data目录下创建文件,其它几个容器都是可以共享数据的。
如果删除了挂载地容器,数据卷并不会被自动删除。如果要删除一个数据卷,必须在删除最后一个还挂载它的容器时显式使用docker rm -v命令来指定同时删除关联地容器。
三、应用部署
1、部署mysql
步骤如下:
-
搜索mysql镜像
docker search mysql
-
拉取mysql镜像
docker pull mysql:5.7
-
运行容器设置端口映射
# 创建mysql目录用于存储mysql数据 mkdir ~/mysql cd ~/mysql
docker run -id \ -p 3307:3306 \ --name c_mysql \ -v ~/mysql/conf:/etc/mysql/conf.d \ -v ~/mysql/logs:/logs \ -v ~/mysql/data:/var/lib/mysql \ -e MYSQL_ROOT_PASSWORD=123456 \ mysql:5.7
参数说明:
-p 3307:3306 将容器的3306端口映射到宿主机的3307端口。
-v 挂载目录
-e MYSQL_ROOT_PASSWORD=123456 初始化root密码
运行容器后,可以进入容器使用mysql客户端连接mysql查看。
docker exec -it 容器ID /bin/bash
mysql -uroot -p
也可以使用navicat等工具来连接mysql:
2、部署tomcat
步骤如下:
-
搜索tomcat镜像
docker search tomcat
-
拉取mysql镜像
docker pull tomcat # 直接拉取最新版
-
运行容器设置端口映射
# 创建tomcat目录用于存储tomcat数据信息 mkdir ~/tomcat cd ~/tomcat
docker run -id --name c_tomcat \ -p 8080:8080 \ -v ~/tomcat:/usr/local/tomcat/webapps \ tomcat
3、部署nginx
-
拉取nginx镜像
docker pull nginx # 直接拉取最新版
-
运行容器设置端口映射
mkdir -p ~/nginx/conf cd ~/nginx/conf vim nginx.conf # 在~/nginx/conf下创建nginx.conf配置文件,将下面的内容黏贴到nginx.conf中 ---------------------------------------------------------------- user nginx; worker_processes auto; error_log /var/log/nginx/error.log notice; pid /var/run/nginx.pid; events { worker_connections 1024; } http { include /etc/nginx/mime.types; default_type application/octet-stream; log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"'; access_log /var/log/nginx/access.log main; sendfile on; #tcp_nopush on; keepalive_timeout 65; #gzip on; include /etc/nginx/conf.d/*.conf; }
docker run -id --name=c_nginx \ -p 80:80 \ -v ~/nginx/conf/nginx.conf:/etc/nginx/nginx.conf \ -v ~/nginx/conf/logs:/var/log/nginx \ -v ~/nginx/conf/html:/usr/share/nginx/html \ nginx
4、部署redis
步骤如下:
-
拉取redis镜像
docker pull redis # 直接拉取最新版
-
运行容器设置端口映射
docker run -id --name c_redis -p 6379:6379 redis
-
使用外部机器连接redis
redis-cli -h 宿主机ip -p 6379
四、构建自己的镜像
常用地创建镜像的方式有两种,分别是:将容器提交为一个镜像、使用Dockerfile创建镜像。
1、Docker镜像原理
首先先思考几个问题:
- Docker 镜像本质是什么?
- Docker 中一个centos镜像为什么只有200MB,而一个centos操作系统的iso文件要几个个G?
- Docker 中一个tomcat镜像为什么有500MB,而一个tomcat安装包只有70多MB
操作系统的组成部分:
- 进程调度子系统
- 进程通信子系统
- 内存管理子系统
- 设备管理子系统
- 文件管理子系统
- 网络通信子系统
- 作业控制子系统
Linux文件系统由bootfs和rootfs两部分组成
- bootfs:包含bootloader(引导加载程序)和 kernel(内核)
- rootfs: root文件系统,包含的就是典型 Linux 系统中的/dev,/proc,/bin,/etc等标准目录和文件
不同的linux发行版,bootfs基本一样,而rootfs不同,如ubuntu,centos等。
Docker镜像是由特殊的文件系统叠加而成,最底端是 bootfs,并使用宿主机的bootfs ,第二层是 root文件系统rootfs,称为base image,然后再往上可以叠加其他的镜像文件。
联合文件系统(Union File System)技术能够将不同的层整合成一个文件系统,为这些层提供了一个统一的视角,这样就隐藏了多层的存在,在用户的角度看来,只存在一个文件系统。
一个镜像可以放在另一个镜像的上面。位于下面的镜像称为父镜像,最底部的镜像成为基础镜像。当从一个镜像启动容器时,Docker会在最顶层加载一个读写文件系统作为容器
因此上面思考的答案是:
Docker 镜像本质是什么?
:是一个分层的文件系统
Docker 中一个centos镜像为什么只有200MB,而一个centos操作系统的iso文件要几个个G?
: Centos的iso镜像文件包含bootfs和rootfs,而docker的centos镜像复用操作系统的bootfs,只有rootfs和其他镜像层
Docker 中一个tomcat镜像为什么有500MB,而一个tomcat安装包只有70多MB
: 由于docker中镜像是分层的,tomcat虽然只有70多MB,但他需要依赖于父镜像和基础镜像,所有整个对外暴露的tomcat镜像大小500多MB
2、提交容器为镜像
我们可以将一个容器转为一个镜像。也可以将一个镜像生成一个本地的压缩文件,在1.6节已经介绍。
我们从远程仓库拉取的官方的ubuntu系统是很纯净的,里面去除了很多不必要的软件,甚至连sudo命令的没有。我们可以运行一个从官网拉取的镜像,并在容器中安装vim、GCC、make等工具,然后将该容器提交为一个镜像。那么之后根据这个镜像运行新的容器时,容器中就会有这些工具了。
docker commit 容器名 或 ID 生成的镜像标签
# 例如
docker commit ubuntu1 myubuntu:lastest
3、使用Dockerfile创建镜像
Dockerfile是一个文本格式的配置文件,用户可以使用Dockerfile来快速创建自定义的镜像。Dockerfile一般由一行行指令组成,并且支持以#开头的注释行;每一条指令构建一层,基于基础镜像,最终构建出一个新的镜像;对于开发人员:可以为开发团队提供一个完全一致的开发环境;对于测试人员:可以直接拿开发时所构建的镜像或者通过Dockerfile文件构建一个新的镜像开始工作了;对于运维人员:在部署时,可以实现应用的无缝移植;
一般而言,Dockerfile主体内容分为四部分:基础镜像信息、维护者信息、镜像操作指令和容器启动时执行指令。
Dockerfile相关命令:
关键字 | 作用 | 备注 |
---|---|---|
FROM | 指定父镜像 | 指定dockerfile基于哪个image构建 |
MAINTAINER | 作者信息 | 用来标明这个dockerfile谁写的 |
LABEL | 标签 | 用来标明dockerfile的标签 可以使用Label代替Maintainer 最终都是在docker image基本信息中可以查看 |
RUN | 执行命令 | 执行一段命令 默认是/bin/sh 格式: RUN command 或者 RUN [“command” , “param1”,“param2”]。RUN命令是在镜像构建时执行的。 |
CMD | 容器启动命令 | 提供启动容器时候的默认命令 和ENTRYPOINT配合使用.格式 CMD command param1 param2 或者 CMD [“command” , “param1”,“param2”]。CMD命令是在容器启动时执行的。 |
ENTRYPOINT | 入口 | 指定镜像的默认入口命令 |
COPY | 复制文件 | build的时候复制文件到image中 |
ADD | 添加文件 | build的时候添加文件到image中 不仅仅局限于当前build上下文 可以来源于远程服务,添加压缩文件时会自动解压。 |
ENV | 环境变量 | 指定build时候的环境变量 可以在启动的容器的时候 通过-e覆盖 格式ENV name=value |
ARG | 构建参数 | 构建参数 只在构建的时候使用的参数 如果有ENV 那么ENV的相同名字的值始终覆盖arg的参数 |
VOLUME | 定义外部可以挂载的数据卷 | 指定build的image那些目录可以启动的时候挂载到文件系统中 启动容器的时候使用 -v 绑定 格式 VOLUME [“目录”] |
EXPOSE | 暴露端口 | 定义容器运行的时候监听的端口 启动容器的使用-p来绑定暴露端口 格式: EXPOSE 8080 或者 EXPOSE 8080/udp |
WORKDIR | 工作目录 | 指定容器内部的工作目录 如果没有创建则自动创建 如果指定/ 使用的是绝对地址 如果不是/开头那么是在上一条workdir的路径的相对路径 |
USER | 指定执行用户 | 指定build或者启动的时候 用户 在RUN CMD ENTRYPONT执行的时候的用户 |
HEALTHCHECK | 健康检查 | 指定监测当前容器的健康监测的命令 基本上没用 因为很多时候 应用本身有健康监测机制 |
ONBUILD | 触发器 | 当存在ONBUILD关键字的镜像作为基础镜像的时候 当执行FROM完成之后 会执行 ONBUILD的命令 但是不影响当前镜像 用处也不怎么大 |
STOPSIGNAL | 发送信号到宿主机 | 该STOPSIGNAL指令设置将发送到容器的系统调用信号以退出。 |
SHELL | 指定执行脚本的shell | 指定RUN CMD ENTRYPOINT 执行命令的时候 使用的shell |
Dockerfile构建命令:
docker build -f ./Dockerfile -t myimage .
# -f 参数用于指定dockerfile的位置,如果在当前目录下切名字为Dockerfile,也可以不指定
# -t target 用于指定生成的镜像名
# .为构建的目录
例1:构建Springboot项目的镜像:
写了一个简单的springboot程序:
可以在浏览器中访问的到:
构建步骤:
1.将项目打包为jar文件,并上传到linux的一个目录下,例如/home/mgh/docker_springboot文件下:
mkdir ~/docker_springboot
2.创建Dokcerfile文件:
vim Dockerfile
3.写Dockerfile:
dockerfile 内容如下
# 由于springboot项目依赖java jdk,因此需要有jdk的环境。也可以是ubuntu或centos,但是其中没有java环境,还需要安装
FROM java:8
# 作者信息,也可以不要
MAINTAINER author<author@hdu.edu.cn>
# 将当前目录下的jar包添加到镜像中,并命名为app.jar
ADD springboot_test-0.0.1-SNAPSHOT.jar app.jar
# 运行springboot项目 也可以是CMD ["java", "-jar", "app.jar"]
CMD java -jar app.jar
4.构建镜像:
docker build -t springboot_test .
5.构建成功
6.运行容器
docker run -id -p 8080:8080 springboot_test
7.在浏览器中访问
例2:构建C++程序
1.创建目录、写一个helloworld程序
mkdir ~/cpp_docker
vim hello.cpp
程序如下,每隔一秒打印一次hello,world
#include <iostream>
#include <unistd.h>
using namespace std;
int main()
{
while(1)
{
cout << "hello,world!" << endl;
sleep(1);
}
return 0;
}
2.创建Dockerfile文件并写入
vim Dockerfile
# 内容如下:
# 基础镜像
FROM ubuntu:18.04
MAINTAINER author<author@hdu.edu.cn>
# 设置环境变量
ENV MYPATH /usr/local/test
# 设置工作目录,设置工作目录后,启动容器,容器所在目录就是工作目录
WORKDIR $MYPATH
# 将当前文件夹下的cpp文件拷贝到工作目录
COPY hello.cpp $MYPATH
# 安装g++ 以及 编译cpp文件。也可以将这三个命令分开写成三条,但是会生成三层,所以不建议
# 在安装软件的时候,系统可能会让你输入y或n来同意或拒绝安装,使用-y参数就是同意安装。不然可能会失败。
RUN apt-get update && \
apt-get -y install g++ && \
g++ hello.cpp -o hello
# 容器启动时执行的命令
CMD ["./hello"]
3.构建镜像
docker build -t cpp_test .
4.运行容器
docker run -it cpp_test
可以看到容器中在打印hello,world。但是退出不了了,可以使用docker stop将这个容停止。
例3:构建Golang程序
将使用gin框架的一个web程序构建为docker镜像:
1.golang代码:
package main
import (
"github.com/gin-gonic/gin"
"net/http"
)
func main() {
engine := gin.Default()
engine.GET("/jige", func(context *gin.Context) {
data := map[string]interface{}{
"name" : "kunkun",
"age" : 23,
"hobby" : "sing jump rap",
}
context.JSON(http.StatusOK, data)
})
engine.Run("0.0.0.0:8080")
}
go.mod
go mod init
go mod tidy
2.将程序打包上传到linux的一个文件中
mkdir ~/docker_golang
#程序文件名 gin_json
3.创建Dockerfile
vim Dockerfile
# dockerfile内容如下
# 基础镜像
FROM golang
MAINTAINER author <author@hdu.edu.cn>
# 设置环境变量
ENV GO111MODULE on
# 设置golang代理否则下载gin框架很可能会失败
ENV GOPROXY https://goproxy.cn
# 设置工作目录
WORKDIR /go/src/gin_json/
# 把当前目录下所以文件拷贝到容器的工作目录
COPY . .
# 安装gin框架依赖
RUN go mod tidy
# 容器启动运行程序
CMD go run main.go
4.构建镜像
docker build -t gotest .
5.运行容器
docker run -id -p 9090:8080 gotest
6.浏览器访问页面
4、配置指令详细介绍:
1.FROM :
指定所创建镜像的基础镜像,比如JAVA程序依赖于java jdk,因此可以选择一个带有java jdk的镜像作为基础镜像。
格式:FROM image 或 FROM image:tag
任何Dockerfile中第一条指令必须为FROM指令。并且,如果在同一个Dockerfile中创建多个镜像时,可以使用多个FROM指令。
为了保证镜像精简,可以选用体积较小的镜像如Alpine或Debian作为基础镜像。
2.ARG :
定义创建镜像过程中使用的变量。
格式:ARG key val 或 ARG key =val
当镜像构建完成后,ARG定义的变量将不再存在(ENV指定的变量将在镜像中保留)。
3.ENV :
指定环境变量,在镜像生成过程中会被RUN指令使用,在镜像启动的容器中也会存在。
格式:ENV key val 或 ENV key=val
指令指定的环境变量在运行时可以被覆盖掉,如:docker run --env key=val built_image
4.LABEL :
LABEL指令可以为生成的镜像添加元数据标签信息。
格式:LABEL key=value key=value …
5.EXPOSE :
声明镜像内服务监听的端口。
格式:EXPOSE port …
例如:
EXPOSE 22 80 8080
该指令只是起到声明作用,并不会自动完成端口映射。
6.ENTRYPOINT :
指定镜像的默认入口命令,该入口命令会在启动容器时作为根命令执行,所有传入值作为该命令的参数。
支持两种格式:
ENTRYPOINT [“executable”, “param1”, “param2”] exec调用执行
ENTRYPOINT command param1 param2 shell中执行
此外,CMD指令指定值将作为根命令的参数。每个Dockerfile中只能有一个ENTRYPOINT,当指定多个时,只有最后一个生效。
7.CMD :
CMD指令用来指定启动容器时默认执行的命令。
支持三种格式:
CMD [“executable”, “param1”, “param2”] 相当于执行executable param1 param2
CMD command param1 param2 在默认的shell中执行,提供给需要交互的应用
CMD [“param1”, “param2”] 提供给ENTRYPOINT的默认参数
每个Dockerfile只能有一条CMD命令。如果指定了多条命令,只有最后一条会被执行。如果用户启动容器时手动指定了运行的命令,则会覆盖掉CMD指定的命令。
例如:
在上面的构建C++程序中,指定了CMD运行hello程序:CMD [“./hello”]
因此如果在运行容器时指定了/bin/bash,那么./hello将会被覆盖掉,hello程序也就不会执行 : docker run -it cpp_test /bin/bash
9.VOLUME :
创建一个数据卷挂载点。
格式: VOLUME [“/data”]
运行容器时可以从本地主机或其它容器挂载数据卷,一般用来存放数据库和需要保持的数据或一些配置文件等。
10.WORKDIR :
为后续的RUN、CMD、ENTRYPOINT指令配置工作目录
格式: WORKDIR dir
在WORKDIR指令中最好使用绝对路径。
11.RUN :
运行指定命令。
格式:
RUN command 或 RUN [“executable”, “param1”, “param2”]
注意后者指令将会被解析为JSON数组,因此必须用双引号。前者默认在shell终端中运行命令,即/bin/bash -c;后者使用exec执行,不会启动shell环境。
指定使用其它终端类型可以通过第二种方式实现,例如 RUN [“/bin/bash”, “-c”, “echo hello”]。
每条RUN命令将在当前基础镜像上执行指定命令,并提交为新的镜像层,如果有多条RUN命令,分开来写将会产生很多层镜像层,因此最后将他们写成一条命令,可以用 \ 来换行。例如:
RUN apt-get update \
&& apt-get install -y libsnappy-dev zliblg-dev libbz2-dev \
&& rm -rf /var/cache/apt \
&& rm -rf /var/lib/apt/lists/*
12.ADD :
添加内容到镜像。
格式: ADD src dest
该命令将复制指定的src路径下内容到容器中的dest路径下。
其中src可以是Dockerfile所在目录的一个相对路径(文件或目录);也可以是一个URL;还可以是一个tar文件,tar文件将会被自动解压为目录。路径支持正则表达式,例如:
ADD *.cpp /code/
13.COPY :
复制内容到镜像。
格式:COPY src dest
复制本地主机的src下内容到镜像中的dest。目录不存在时,会自动创建。
路径同样支持正则表达式。
COPY与ADD命令功能相似,当使用本地目录为源目录时,推荐使用COPY。
注意:在构建镜像时最好保证指定目录(命令为:docker build -t test ., 最后那个.就是指定当前目录为构建目录)下没有其它不需要的文件,因为在构建镜像时是由Docker守护进程来执行的,因此客户端将会把指定目录下的所有内容都发送给Docker守护进程,如果当前目录下存在不需要的文件,将会拖慢镜像的构建。
5.最佳实践
所谓最佳实践,就是从需求出发,来定制适合自己、高效的镜像。
精简镜像用途:尽量让每个镜像的用途都比较单一,避免构造大而复杂。
选用合适的基础镜像:容器的核心是应用。选择过大的父镜像(如Ubuntu系统镜像)会造成最终生成应用镜像的臃肿,推荐选用瘦身过的应用镜像(如node:slim),或者较为小巧的系统镜像(如alpine、busybos或debian);
正确使用版本号:使用明确的版本号信息,如1.0,2.0,而非依赖于默认的lastest。通过版本号可以避免环境不一导致的问题;
减少镜像层数:尽量合并RUN、AD和COPY指令。
**及时删除临时文件和缓存文件:**特别是在执行apt-get命令后,/var/cache/apt下面会缓存了一些安装包;
提高生成速度:减少内容目录下不必要的文件。
更多推荐
所有评论(0)