搞事情系列文章主要是为了继续延续本身的 “T” 字形战略所作,同时也表明着毕设相关内容的学习总结。本文章是
Docker
部分的第一篇,主要是给本身解释与Docker
有关的内容。python
原文地址:PJ 的 iOS 开发平常linux
虚拟化技术是一种将计算机物理资源进行抽象、转换为虚拟的计算机资源提供给程序使用的技术。这些资源包括了 CPU 提供的运算控制资源,硬盘提供的数据存储资源,网卡提供的网络传输资源等。nginx
保证程序跨平台兼容,也就是要保证操做系统或物理硬件所提供的接口调用方式一致,程序便不须要兼容不一样硬件平台的接口。此时忽然想到,使用 Swift
编写 iOS app 时,构建出包后老是会带上 Swift
的整个运行时,以保证随着 iOS 系统版本的升级 app 的正常运行,因其 ABI
并未稳定,还不能内置在操做系统中。git
可将虚拟化技术运用于计算机资源的管理,其中最实用的就是“虚拟内存”虚拟化技术可以提升计算机资源的使用率,是指利用虚拟化,能够将原来程序用不到的一些资源拿出来,分享给另一些程序,让计算机资源不被浪费。github
主要分为两大类:硬件虚拟化和软件虚拟化。web
硬件虚拟化:好比假设 iOS 基于的 arm 架构 CPU 可以运行基于 x86 架构的 macOS 应用程序,这是由于 CPU 可以将另一个平台的指令集转换为自身的指令集执行(但实际上并不可能)。sql
软件虚拟化:在 2018 WWDC 中,宣布能够在 UIKit
层面提供一部分把 iOS app 转移到 macOS app 中的特性,能够理解为是 Apple 在 Xcode 层面协助开发者构建了迁移代码,帮开发者解决了不一样平台指令的转换。也就是说,软件虚拟化其实是经过一层夹杂在应用程序和硬件平台上的虚拟化实现软件来进行指令的转换。docker
其它虚拟化技术的分类:shell
VMware
、PD
;Python
的虚拟环境;虚拟机一般说法是经过一个虚拟机监视器( Virtual Machine Monitor ) 的设施来隔离操做系统与硬件或应用程序和操做系统,以达到虚拟化的目的。这个虚拟机监视器,一般被称为:Hypervisor
。django
虚拟机有一个永远都逃不掉的问题:性能低下。这种效率的低下有时候是没法容忍的,故真实的虚拟机程序经常不彻底遵照 Hypervisor
的设计结构,而是引入一些其它技术来解决效率低下问题,好比解释执行、即时编译(Just In Time)运行机制,但这些技术的引入已不属于虚拟化的范畴了。
按分类或者实现方式来讲,容器技术应该属于操做系统虚拟化,也就是在由操做系统提供虚拟化的支持。总的来讲,容器技术指的是操做系统自身支持一些接口,可以让应用程序间能够互不干扰的独立运行,并可以对其在运行中所使用的资源进行干预。
那这也不该该被称为“容器”呀?是的,这里所谓的容器指的是因为应用程序的运行被隔离在了一个独立的运行环境之中,这个独立的运行环境就好似一个容器,包裹了应用程序。
容器这么火爆,火到一心扑在 iOS 上的我都要好好梳理一番,很重要的一个缘由是其在运行性能上远超虚拟机等其它虚拟化实现,甚至在运行效率上与真实运行在物理平台的应用程序不相上下。但注意,容器技术并无进行指令转换,运行爱容器中的应用程序自身必须支持在真实操做系统上运行,也就是必须遵照硬件平台的指令规则。
曾经看到一篇文章说 linux
内核命名空间的改进,直接推进了容器的最大化发展。
利用内核命名空间,从进程 ID 到网络名称,一切均可在 Linux 内核中实现虚拟化。新增的用户命名空间“使得用户和组 ID 能够按命名空间进行映射。对于容器而言,这意味着用户和组能够在容器内部拥有执行某些操做的特权,而在容器外部则没有这种特权。”Linux 容器项目 (LXC) 还添加了用户亟需的一些工具、模板、库和语言绑定,从而推进了进步,改善了使用容器的用户体验。LXC 使得用户可以经过简单的命令行界面轻松地启动容器。(来源
redhat
官网)
容器因为没有虚拟操做系统和虚拟机监视器这两个层次,大幅减小了应用程序带来的额外消耗。因此在容器中的应用程序其实彻底运行在了宿主操做系统中,与其它真实运行在其中的应用程序在指令运行层面是彻底没有任何区别的。
Docker
的核心组成能够理解为一个只读的文件包,其中包含了虚拟环境运行的最原始文件系统的内容。
由于 Docker
采用 AUFS
做为底层文件系统的实现,实现了一种增量式的镜像结构。每次对镜像内容修改,Docker
都会将这些修改铸形成一个镜像层,而一个镜像本质上是由其下层全部的镜像层所组成的,而每个镜像层单独拿出来,均可以与它之下的镜像层组成一个镜像。正是因为这种结构,Docker
的镜像本质上是没法被修改的,由于因此的镜像修改只会产生新的镜像,而不是更新原有的镜像。
在容器技术中,容器是用来隔离虚拟环境的基础设施,但在 Docker
中,被引伸为隔离出来的虚拟环境。若是咱们把镜像理解为类,则容器为实例对象。镜像内存放的是不可变化的东西,当以他们为基础的容器启动后,容器内也就成为类一个“活”的空间。
Docker
的容器应该有三项内容组成:
Docker
镜像;在 Docker
中可对每一个容器进行单独的网络配置,也可对各个容器间创建虚拟网络,将数个容器包裹其中,同时与其它网络环境隔离,而且 Docker
还能在容器中构造独立的 DNS
,咱们能够在不修改代码和配置的前提下直接迁移容器。
在以往的虚拟机中,大部分状况下都直接使用虚拟机的文件系统做为应用数据等文件的存储位置,但并未是彻底安全的,当虚拟机或容器出现问题致使文件系统没法使用时,虽可直接经过快速的镜像进行重制文件系统以致于恢复,但数据也就丢失了。
为保证数据的独立性,一般会单独挂在一个文件系统来存放数据,得意与 Docker
底层的 Union File System
技术,咱们能够不用管相似于搞定挂载在不一样宿主机中实现的方法、考虑挂载文件系统兼容性、虚拟机操做系统配置等问题。
Docker
镜像全部的 Docker
镜像都是按照 Docker
所设定的逻辑打包的,也是收到 Docker Engine
所控制。常见的虚拟机镜像都是由其它用户经过各自熟悉的方式打包成镜像文件,公布到网上再被其它用户所下载后,恢复到虚拟机中的文件系统中,但 Docker
的镜像必须经过 Docker
来打包,也必须经过 Docker
下载或导入后使用,不能单独直接恢复成容器中的文件系统。这样,咱们就能够直接在服务器之间传递 Docker
镜像,并配合 Docker
自身对镜像的管理功能,使得在不一样的机器中传递和共享变得很是方便。
每个记录文件系统修改的镜像层 Docker
都会根据它们的信息生产一个64位的 hash
码,正是由于这个编码,能够可以区分不一样的镜像层并保证内容和编码是一致的,咱们能够在镜像之间共享镜像层。当 A
镜像依赖了 C
镜像,且 B
镜像也依赖了 C
镜像,在实际使用过程当中,A
和 B
两个镜像是能够公用 C
镜像内部的镜像层的。
$ docker images
复制代码
能够分为三部分:
Docker
对容器的设计和定义是微型容器而不是庞大臃肿的完整环境,全部一般只会在一个容器中运行一个应用程序,可以大幅下降程序之间互相的影响,利用容器技术控制每一个程序所使用的资源。在 Docker
的设计中,容器的生命周期与容器中 PID
为 1 这个进程由密切的关系,容器的启动本质上能够理解为这个进程的启动,而容器的中止也就意味着这个进程的中止。
经过镜像运行容器时并非当即把镜像里全部内容拷贝到容器所运行的沙盒文件系统中,而是利用 UnionFS
将镜像以只读方式挂载到沙盒文件系统中,只有在容器对文件的修改时,修改才会体现到沙盒环境上。
docker pull ubuntu
复制代码
docker inspect ubuntu
复制代码
docker search django
复制代码
docker rmi ubuntu
复制代码
$ docker create ubuntu
复制代码
若是咱们以前选择的 docker pull
容器并非默认的 latest
版本,而是手动选择了一个版本,那镜像的名字将会好比 nginx:1.12
,对于后续的操做都十分的不方便,对此,咱们能够采用 --name
进行重命名:
$ docker create --name nginx nginx:1.12
复制代码
$ docker start ubuntu
复制代码
经过 docker run
可将上述两个命令进行合并:
$ docker run --name nginx nginx:1.12
复制代码
以上命令跑起来的容器运行都是运行在前台,若是咱们想要容器运行在后台,能够经过 -d
,其是 -detach
的简称,告诉 Docker
在启动后将程序和控制进行分离。:
$ docker run -d ubuntu
复制代码
列出运行中的全部容器
$ docker ps
复制代码
列出全部容器
$ docker ps -a/-all
复制代码
其中打印出的列表须要注意的是 STATUS 字段,常见的状态表示有三种:
$ docker stop ubuntu
复制代码
容器中止后,其维持的文件系统沙盒环境会一直保存,内部被修改的内容也会被保留。经过 docker start
将容器继续启动。
当须要把容器彻底删除容器,可使用:
$ docker rm ubuntu
复制代码
但在运行中的容器默认状况下是不能被删除的,但咱们能够经过如下命令进行删除:
$ docker rm -f ubuntu
复制代码
Docker
与其它虚拟机不一样,其所定位的轻量级设计讲究随用随开,随关随删,当咱们短期内不须要使用容器时,最佳的作法是删除它而不是仅仅中止它。
若是咱们要对程序作一些环境配置,彻底能够直接将这些配置打包至一个新的镜像中,下次直接使用该镜像建立容器便可。对于一些重要的文件资料,不能随着容器的删除而删除,可使用 Docker
中的数据卷来单独存放。
$ docker run -it --name ubuntu ubuntu
复制代码
$ docker exec -it ubuntu /bin/bash
复制代码
-i
表示保持咱们的输入流;-t
表示启用一个伪终端,造成咱们与 bash 的交互。当容器运行在后台,想要在将当前的输入输出流链接到指定的容器上,能够这么作:
$ docker attach ubuntu
复制代码
经过 docker attach
启动的容器,能够理解为与 docker run -d
作了相反的事情,把当前容器从后台拉回了前台。
在 Docker
网络中,有三个比较核心的概念,造成了 Docker
的网络核心模型,即容器网络模型(Container Network Model):
IP
路由表、防火墙等;Docker
内部的虚拟子网,网络内的参与者相互可见并可以进行通信。须要注意的是,这种虚拟网络与宿主机存在隔离关系。Docker
的网络实现目前官方提供了五种网络驱动:
Docker
的集群模块 Docker Swarm
来搭建的跨 Docker Daemon
网络,能够经过它搭建跨物理主机的虚拟网络,从而让不一样物理机中运行的容器感知不到多个物理机的存在。网络剩余内容将在下篇文章中继续进行......
学习到这里后,开始对 Docker
所谓“轻量级”的主打理念有了一个初步的认识,准备利用 Docker
的这一特性作一个 Swift
编译服务,主要想利用 Vapor
/Perfect
(这两个到底选哪个还需调研)来搭建 HTTP 服务,接收传入的代码文本,执行并返回结果。
思考了一下,须要:
Swift
能力的 Docker
镜像;Vapor
/Perfect
框架的 Docker
镜像;Nginx
web 服务器的 Docker
镜像;这一套下来后,将从新发布一个“开箱即用”的提供 Swift
编译服务的 Docker
镜像~想一想就是个很是美好的事情呢!接下来开始第一步
Swift
能力的 Docker
镜像以前有看到的文章说直接能够在 Ubuntu
上构建本身的 Swift
版本,因此个人第一步先去找一个 Ubuntu
镜像,这点很是容易:
$ docker pull ubuntu
$ docker run -it --name ubuntu ubuntu /bin/bash 复制代码
成功进入到 bash 后,继续下一步。找到一个万能命令,根据这个命令能够先把编译 Swift
须要的相关依赖都下载完成:
sudo apt-get install git cmake ninja-build clang python uuid-dev libicu-dev icu-devtools libbsd-dev libedit-dev libxml2-dev libsqlite3-dev swig libpython-dev libncurses5-dev pkg-config
复制代码
接着,下载 Swift
源码:
git clone https://github.com/apple/swift.git
复制代码
再下载项目依赖的其它源码:
./utils/update-checkout --clone
复制代码
完成后,便可开始利用源码中的工具进行编译和测试!
utils/build-script -t
复制代码
此处将会经历漫长的等待。二十分钟后,我获得了两个报错:
clang: error: unable to execute command: Killed
clang: error: linker command failed due to signal (use -v to see invocation)
ninja: build stopped: subcommand failed.
utils/build-script: fatal error: command terminated with a non-zero exit status 1, aborting
复制代码
clang: error: unable to execute command: Killed
clang: error: linker command failed due to signal (use -v to see invocation)
[1747/3019] Linking CXX shared library lib/libLTO.so.7svn
FAILED: lib/libLTO.so.7svn
复制代码
看提示是一些依赖库出了问题,刚开始觉得更新下对应的依赖库就完事了,没想到在网上竟然找到不对应的报错提示!这对于第一次手动编译 Swift
的玩家来讲十分的不友好,折腾了一下子后放弃!
此时,又看到一篇文章有说能够直接利用 Swift
官网已经构建完成的二进制文件进行使用,地址在此 swift.org/download/ ,在 Docker
中能够经过 wget
进行下载。但因未找到 Swift 4.2.1
的正确下载地址,而且也担忧直接修改以往版本下载地址进行猜想地址不对,在宿主机上下载完成后,经过 docker cp /path dockerContainer:/path
命令把文件夹传递到了容器中。
在添加 PATH
我又遇到了以下错误:
swift: error while loading shared libraries: libatomic.so.1: cannot open shared object file: No such file or directory
复制代码
swift: error while loading shared libraries: libedit.so.2: cannot open shared object file: No such file or directory
复制代码
几乎已经把 SO 上全部的解决方案进行了尝试,皆无果,有 issue
说估计是 Docker 自己的问题,折腾了好一下子,遂放弃。
当时觉得这已是最后一种方案,因此折腾了特别久,没想到其实 Apple 官方竟然维护了一套 swift-docker
,开箱即用,特别香!!!
$ docker pull swift
$ docker run --privileged -i -t --name swiftfun swift:latest /bin/bash
复制代码
至此,第一步已经完成!这回都省去了本身构建镜像的工做了~