Docker容器学习梳理--基础知识(1)
Docker是PaaS 提供商 dotCloud 开源的一个基于 LXC 的高级容器引擎,源代码托管在 Github 上, 基于go语言并遵从Apache2.0协议开源。 Docker是通过内核虚拟化技术(namespace以及cgroups等)来提供容器的资源隔离与安全保障。由于Docker通过操作系统层的虚拟化实现隔离,所以Docker容器在运行时,不需要类似虚拟机( VM)额外的操作系统开销,提高资源利用率。
原理:建立-->传送-->运行
架构:C/S架构
组件:镜像(Image)、容器(Container)、仓库(Repository)
Docker与VM的区别:
docker与Openstack的对比
Docker用途:简单配置、代码流水线管理、开发效率、应用隔离、服务器整合、调试能力、多租户、快速部署
Docker改变了什么? 面向产品:产品交付 面向开发:简化环境配置 面向测试:多版本测试 面向运维:环境一致性 面向架构:自动化扩容
Docker环境的安装部署 环境准备(centos7)
yum install -y docker
systemctl start docker
systemctl enable docker
镜像的查看(docker images信息结果包括:镜像仓库、标签、镜像ID、创建时间、镜像大小 )
[root@linux-node2 ~]# docker images
REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE
docker.io/centos latest 60e65a8e4030 36 hours ago 196.6 MB
docker.io/nginx latest 813e3731b203 9 days ago 133.8 MB
docker.io/registry latest a8706c2bfd21 2 weeks ago 422.8 MB
镜像的导出、导入和下载(可以将本机下载的镜像导出,然后将导出文件上传到别的机器上,在别的机器上进行镜像导入)
[root@linux-node2 ~]# docker pull centos
[root@linux-node2 ~]# docker save centos > /opt/centos.tar.gz
将linux-node2的镜像导出文件上传到linux-node1机器上,然后在linux-node1机器上导入
[root@linux-node1 ~]# docker load < /opt/centos.tar.gz
镜像的删除(rmi后面可以跟多个id,用空格隔开) docker rmi container_id
[root@linux-node2 ~]# docker rmi 813e3731b203
首次创建一个简单的容器
[root@linux-node2 ~]# docker run centos /bin/echo "hehe"
hehe
命令解读:使用centos镜像,run执行命令,使用echo命令输出hehe
查看容器状态 可以使用docker ps只能看见存活的容器,docker ps -a 查看全部的容器,结果信息表示: 容器ID、使用的镜像、执行的命令、创建的时间、状态、端口、名称(如果不指定,自动生成)
[root@linux-node2 ~]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
daeb4d7f7aab centos "/bin/echo hehe" About a minute ago Exited (0) About a minute ago insane_einstein
创建容器 --name:指定容器名称 -t :分配一个tty终端 -i :容器的标准输保持打开的状态
[root@linux-node2 ~]# docker run --name mydocker -t -i centos /bin/bash
[root@94ab7a046f7c /]# ps aux
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.0 0.1 11772 1872 ? Ss 03:42 0:00 /bin/bash
root 14 0.0 0.0 35888 1472 ? R+ 03:43 0:00 ps aux
这种方式创建自动进入容器,开启的容器只执行/bin/bash;
在容器中查看主机名
[root@94ab7a046f7c /]# hostname
94ab7a046f7c
[root@94ab7a046f7c /]# exit
启动、停止容器
[root@linux-node2 ~]# docker stop ID
进入容器
[root@linux-node2 ~]# docker attach 94ab7a046f7c
删除容器
[root@linux-node2 ~]# docker rm ID/名称
加-f 强制删除,包括正在运行中的容器
映射
随机映射 端口的映射是系统自动分配的?
[root@linux-node2 ~]# docker run -d -P nginx
90316d97ee975b4e62e1927a9fb31f20703556b1a3ea07880d0c68dcb5bbd3bb
[root@linux-node2 ~]# docker ps -l
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
90316d97ee97 nginx "nginx -g 'daemon off" 25 seconds ago Up 23 seconds 0.0.0.0:32769->80/tcp, 0.0.0.0:32768->443/tcp ecstatic_almeida
指定映射 指定端口的映射
[root@linux-node2 ~]# docker run -d -p 81:80 nginx
0294a8f5b4fc81ba31383a8eb98ec62b136826eba92360c84afd87bf1bf819fc
[root@linux-node2 ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
0294a8f5b4fc nginx "nginx -g 'daemon off" 11 seconds ago Up 10 seconds 443/tcp, 0.0.0.0:81->80/tcp admiring_ramanujan
查看日志
[root@linux-node2 ~]# docker log +ID
数据管理
数据卷 默认挂载目录 创建一个数据卷,名称是volume-test1,挂载到data下默认挂载目录
[root@linux-node2 ~]# docker run -it --name volume-test1 -v /data centos
[root@1768d6414cfc /]# ls -l /data/
total 0
打开一个新的窗口
列出容器的所有信息,查看mounts模块
[root@linux-node2 ~]# docker inspect 1768d6414cfc
"Mounts": [
{
"Name": "55c97df0276bb8879398b4e7286fc41f9872e9203267da7e23060e24ba06d167",
"Source": "/var/lib/docker/volumes/55c97df0276bb8879398b4e7286fc41f9872e9203267da7e23060e24ba06d167/_data",
"Destination": "/data",
"Driver": "local",
"Mode": "",
"RW": true
}
],
查找挂载点并进入
查看挂载的位置
[root@linux-node2 ~]# ll /var/lib/docker/volumes/55c97df0276bb8879398b4e7286fc41f9872e9203267da7e23060e24ba06d167/_data
总用量 0
进入到挂载点
[root@linux-node2 ~]# cd /var/lib/docker/volumes/55c97df0276bb8879398b4e7286fc41f9872e9203267da7e23060e24ba06d167/_data
创建一个cgt测试,并重新回到容器中查看
[root@linux-node2 _data]# mkdir cgt
去容器中查看
[root@1768d6414cfc /]# ls -l /data/
total 4
drwxr-xr-x 2 root root 4096 Jan 4 14:04 cgt
指定挂载目录
将/opt挂载到/opt目录下
[root@linux-node2 ~]# docker run -it --name volume-test1 -v /opt:/opt centos
指定权限
只需要在挂载后面加上权限即可。
加读写rw;只读ro
[root@linux-node2 ~]# docker run -it --name volume-test1 -v /opt:/opt:rw centos
挂载单个文件
记录历史记录
[root@linux-node2 ~]# docker run -it -v ~/.bash_history:/.bash_history centos
数据卷容器
让一个容器可以访问另一个容器的数据卷
启动两个容器
启动nfs容器,挂在一个卷,使用-d直接在后台执行
[root@linux-node2 ~]# docker run -d --name nfs -v /data centos
209bc89b365ad6bc1eeae693ada01c04c2d08e9ee2b8816e624882944c116126
启动test1容器,挂载到nfs的数据卷容器上,
[root@linux-node2 ~]# docker run -it --name test1 --volumes-from nfs centos
[root@5e399198d6a8 /]# ls /data/
查看没内容
找到nfs容器的挂载点
(可以使用名称,不仅仅是ID)
找到nfs容器的ID
[root@linux-node2 opt]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
209bc89b365a centos "/bin/bash" 2 minutes ago Exited (0) 2 minutes ago nfs
找到nfs容器的挂载点
在test1上查看
到test1上查看
[root@5e399198d6a8 /]# ls /data/
cgt
注意:数据卷容器不论停止还是开启,不影响其他容器挂载使用 如何制作镜像 方式一:手动构建容器 1)创建一个容器mynginx,使用centos镜像
[root@linux-node2 ~]# docker run --name mynginx -it centos
[root@f9c7dfb6f552 /]# rpm -ivh http://mirrors.aliyun.com/epel/epel-release-latest-7.noarch.rpm
[root@f9c7dfb6f552 /]# yum -y install nginx
[root@f9c7dfb6f552 /]# exit
exit
2)基于mynginx容器做一个镜像mynginx:v1
[root@linux-node2 ~]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
f9c7dfb6f552 centos "/bin/bash" 3 minutes ago Exited (0) 15 seconds ago mynginx
基于mynginx这个容器做一个镜像
[root@linux-node2 ~]# docker commit -m "my nginx" f9c7dfb6f552 cgt/mynginx:v1
3f3adc859b77b2b47c3631229761bee6c7066f1c708bc01c5173c2ef5c0adce8
提交镜像,同时打一个标签叫mynginx:v1,cgt相当于你向github上提交的用户名
查看镜像
[root@linux-node2 ~]# docker images
REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE
cgt/mynginx v1 3f3adc859b77 About a minute ago 326.4 MB
3)基于mynginx:v1创建一个容器mynginxv1
目的是修改nginx不让其在后台运行
[root@linux-node2 ~]# docker run -it --name nginxv1 cgt/mynginx:v1
[root@ea64c5855006 /]# vi /etc/nginx/nginx.conf
daemon off; # 不再后台运行
[root@ea64c5855006 /]# exit
exit
[root@linux-node2 ~]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
ea64c5855006 cgt/mynginx:v1 "/bin/bash" 2 minutes ago Exited (0) 42 seconds ago nginxv1
4)基于mynginxv1提交mynginxv2版本
重新提交V2版本
[root@linux-node2 ~]# docker commit -m "my nginx" ea64c5855006 cgt/mynginx:v2
a480cdf9055ec4e640c65df6404c6ba42903ea77198a26cec75eef0e4965fe67
查看V2镜像
[root@linux-node2 ~]# docker images
REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE
cgt/mynginx v2 a480cdf9055e 25 seconds ago
5)基于mynginxv2镜像,创建mynginxv2容器
启动容器,-d后台运行,-p指定端口 在后面是镜像,最后是命令(因为是yum安装的,可以直接写nginx,如果不是yum,那要写绝对路径)
[root@linux-node2 ~]# docker run -d -p 82:80 cgt/mynginx:v2 nginx
4eaf8a19034a673100f9355504628fad45e6ecbab91615afd6cb4e7a18b82171
[root@linux-node2 ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
4eaf8a19034a cgt/mynginx:v2 "nginx" 15 seconds ago Up 14 seconds 0.0.0.0:82->80/tcp elegant_leakey
可以在浏览器访问82端口
方式二:Dockerfile
1)Dockerfile包含的信息
基础镜像信息 维护者信息 镜像操作指令 容器启动时执行指令
2)文件的编写
[root@linux-node2 ~]# mkdir /opt/dockerfile/nginx/ -p
[root@linux-node2 ~]# cd /opt/dockerfile/nginx/
将index.html上传到此处
[root@linux-node2 nginx]# vim Dockerfile
# This is docker file
# version v1
# Author wangshibo
# Base image(基础镜像)
FROM centos
# Maintainer(维护者信息)
MAINTAINER wangshibo 2134728394@qq.com
# Commands(执行命令)
RUN rpm -ivh http://mirrors.aliyun.com/epel/epel-release-latest-7.noarch.rpm
RUN yum -y install nginx
# Add(添加文件)
ADD index.html /usr/share/nginx/html/index.html # index.html是自己编写的文件,放在后面的目录中,因为yum安装后Documentroot是在这里
RUN echo "daemon off;" >>/etc/nginx/nginx.conf
EXPOSE 80 # 对外的端口
CMD ['nginx'] # 执行的命令
3)构建容器,并运行
建立newnginx容器,-t:标签,执行/opt/dockerfile/nginx/下面的默认的Dockerfile文件
[root@linux-node2 nginx]# docker build -t cgt/mynginx:v3 /opt/dockerfile/nginx/
[root@linux-node2 nginx]# docker run -d -p 83:80 cgt/mynginx:v3
-------------------------------------------------------------------------------------------------------------------------------
Docker是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的Linux机器上,也可以实现虚拟化。当你真正投入容器Docker的怀抱,不但可以发现它能解决很多问题,而且还具有众多的优点:
1)它是不可变的-操作系统,库版本,配置,文件夹和应用都是一样的。您可以使用通过相同QA测试的镜像,使产品具有相同的表现。
2)它是轻量级的-容器的内存占用非常小。不需要几百几千MB,它只要对主进程分配内存再加上几十MB。
3)它很快速-启动一个容器与启动一个单进程一样快。不需要几分钟,您可以在几秒钟内启动一个全新的容器。
但是,许多用户依然像对待典型的虚拟机那样对待容器,似乎都忘记了除了与虚拟机相似的部分,容器还有一个很大的优点:它是一次性的。 这个“特性”本身促使用户改变他们关于使用和管理容器的习惯;下面将会说明下在容器中不应该做这些事,以确保最大地发挥容器的作用。
1)不要在容器中存储数据 – 容器可能被停止,销毁,或替换。一个运行在容器中的程序版本1.0,应该很容易被1.1的版本替换且不影响或损失数据。有鉴于此,如果你需要存储数据,请存在卷中,并且注意如果两个容器在同一个卷上写数据会导致崩溃。确保你的应用被设计成在共享数据存储上写入。
2)不要将你的应用发布两份 – 一些人将容器视为虚拟机。他们中的大多数倾向于认为他们应该在现有的运行容器里发布自己的应用。在开发阶段这样是对的,此时你需要不断地部署与调试;但对于质量保证与生产中的一个连续部署的管道,你的应用本该成为镜像的一部分。记住:容器应该保持不变。
3)不要创建超大镜像 – 一个超大镜像只会难以分发。确保你仅有运行你应用/进程的必需的文件和库。不要安装不必要的包或在创建中运行更新(yum更新)。
4)不要使用单层镜像 – 要对分层文件系统有更合理的使用,始终为你的操作系统创建你自己的基础镜像层,另外一层为安全和用户定义,一层为库的安装,一层为配置,最后一层为应用。这将易于重建和管理一个镜像,也易于分发。
5)不要为运行中的容器创建镜像 – 换言之,不要使用“docker commit”命令来创建镜像。这种创建镜像的方法是不可重现的也不能版本化,应该彻底避免。始终使用Dockerfile或任何其他的可完全重现的S2I(源至镜像)方法。
6)不要只使用“最新”标签 – 最新标签就像Maven用户的“快照”。标签是被鼓励使用的,尤其是当你有一个分层的文件系统。你总不希望当你2个月之后创建镜像时,惊讶地发现你的应用无法运行,因为最顶的分层被非向后兼容的新版本替换,或者创建缓存中有一个错误的“最新”版本。在生产中部署容器时应避免使用最新。
7)不要在单一容器中运行超过一个进程-容器能完美地运行单个进程(http守护进程,应用服务器,数据库),但是如果你不止有一个进程,管理、获取日志、独立更新都会遇到麻烦。
8)不要在镜像中存储凭据。使用环境变量 –不要将镜像中的任何用户名/密码写死。使用环境变量来从容器外部获取此信息。
9)使用非root用户运行进程 – “docker容器默认以root运行。(…)随着docker的成熟,更多的安全默认选项变得可用。现如今,请求root对于其他人是危险的,可能无法在所有环境中可用。你的镜像应该使用USER指令来指令容器的一个非root用户来运行。”
10)不要依赖IP地址 – 每个容器都有自己的内部IP地址,如果你启动并停止它地址可能会变化。如果你的应用或微服务需要与其他容器通讯,使用任何命名与(或者)环境变量来从一个容器传递合适信息到另一个。
- 微信小程序,开发大起底
- Netty粘包拆包解决方案
- 为什么要用 Node.js
- JavaScript定时器:setTimeout与setInterval 定时器与异步循环数组
- 深入理解javascript原型和闭包(1)——一切都是对象
- 程序员面试50题(2)—二元查找树的后序遍历结果[数据结构]
- 总结了一些指针易出错的常见问题(一)
- Eureka 服务上下线监控
- 程序员面试50题(1)—查找最小的k个元素[算法]
- Netty4自带编解码器详解
- C和指针小结(C/C++程序设计)
- Netty-整合Protobuf高性能数据传输
- Netty-整合kryo高性能数据传输
- 40个重要的HTML 5面试问题及答案
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- python数据化运营分析实例---销售预测
- Leetcode 1444. 切披萨的方案数(DP,类似石材切割,二维前缀和)
- Python生成内涵图片
- Linux 下makefile实战 ——编写真实的C项目
- MySQL8功能详解——Common table expression (CTE)
- 游戏数据分析
- MySQL8功能详解——隐藏索引
- python 操作excel(附案例)
- 如何在 Spring Boot 中 读写数据
- MyBatis 多表操作
- 从0打造wordpress插件wp2oc fileshare (1) – 将wp存储后端做进owncloud
- Python 爬虫保存图片
- 抛物线法、牛顿法、弦截法求根实例
- org.springframework.web.client.ResourceAccessException: I/O error on POST request....
- 升级MySQL InnoDB Cluster的元数据