dockerd/daemon.go start() loadDaemonCliConfig(opts) 里 daemon.MergeDaemonConfigurations(config, flags, opts.configFile)将配置文件设置的参数和命令参数合并。 过了好多代码,感觉都是配置啥的就不看具体干啥了。 setDefaultUmask() 设置umask 0022,把goup和other的写权限干掉了。 daemon.CreateDaemonRoot(cli.Config) 先获取docker daemon根目录 默认/var/lib/docker setupRemappedRoot 根据配置映射容器用户和组的 这个参数默认是空的,也就是不映射 如果设置了这个参数 parseRemappedRoot就是解析参数的,有四种格式 username username:groupname uid uid:gid 然后解析/etc/passwd和/etc/group看看参数对不对。其中解析是否是defaultIDSpecifier 就是个'default',然后映射的host用户为dockremap。 也就是RemappedRoot这个参数传个default就行了,使用docker创建好的账户 idtools.AddNamespaceRangesUser(defaultRemappedID)就是判断是否有default的用户,没有就创建 uidMaps, gidMaps, err = idtools.CreateIDMappings(username, groupname) 这个从/etc/subuid和/etc/subgid获取,根据username判断是第一个 startid是uid是第二个,length还不知道干啥的第三个 ALL不知道干啥的 返回了所有的行,就是所有用户 createIDMap返回IDMap,ContainerID开始是0然后后边的都加length。hostid,就是第二个startid, size 是length. 然后setupRemappedRoot就完了,返回了俩idmap idtools.GetRootUIDGID(uidMaps, gidMaps) 里边就一个ToHost(0, uidMap)这个单个的时候就是返回之前的hostid就是startid对应host上的uid, 之前的ALL的话,好像还是只返回了第一个的hostid setupDaemonRoot(config, realRoot, rootUID, rootGID) 修改docker的根目录权限为711 RemappedRoot 为空就直接返回了。不空的话创建一个config.Root目录在docker根目录下。目录名为rootUID.rootGID,权限700.然后好像判断目录下的rootUID都有访问权限,这个应该是为已经有这个目录的判断 然后CreateDaemonRoot完结撒花,设置了一下目录,用户的映射

Continue

东西太多了,大体过了一下,感觉会少了很多东西。有一些三方库,也没去看库怎么用。就看函数名大体猜一下功能。 完全就是从main函数一步一步往下看,这种看法就是缺少一个大局的认识,开始会有很多不理解的做法。 cmd/dockerd/docker.go reexec.Init() 必须要提前调用的方法,用来初始化。如果初始化过了就会返回true,main函数也退出了。 判断是否调用过,就是看看registeredInitializers里有没有os.Args[0]的key。 如果有调用value,没有直接返回false,接着走main函数 具体value是个啥函数,慢慢看.里边还有个Register(函数用来往registeredInitializers里添加值。 cmd := newDaemonCommand() cmd.Execute() 这里一看就跟client的结构一样,突然就感觉好看多了。。 daemonOptions daemon.NewConfig() 返回一个Config,所有配置应该都在这,太多了,也看不到啥意思先过了。 cliflags.NewCommonOptions() 对应client TLS相关的东西,这里一样。 其他都一样。 opts.daemonConfig.InstallFlags(flags) 定义都有哪些参数,太多不看,在help命令里应该是有的。配置了对应的Config里边的字段。 看看return runDaemon(opts) daemonCli := NewDaemonCli() 返回一个DaemonCli type DaemonCli struct { *daemon.Config configFile *string flags *pflag.FlagSet api *apiserver.Server d *daemon.Daemon authzMiddleware *authorization.Middleware // authzMiddleware enables to dynamically reload the authorization plugins } err = daemonCli.start(opts) 这里流程就完了。详细看看start是干嘛的

Continue

哈哈,找了个跨平台的游戏框架玩玩。 在mac平台上安装试了一下。下载需要注册,第一次启动也需要填注册的账号,所以还是注册了。 安装完启动输入账号,完成后创建一个项目。直接点击是使用的手机模拟器启动的。 官方给出的命令启动方法,-no-console YES是不显示debug信息。 "/Applications/CoronaSDK/Corona Simulator.app/Contents/MacOS/Corona Simulator" ~/CoronaApps/MyApp 作为桌面软件启动的时候,还是要先开模拟器编译通过后,菜单选择File → Build → macOS.填填选项。选择 Open application编译完启动,或者编译完手动启动也行。

Continue

今天手贱升级了一个pkg版本,从pkg-1.9.3升级到pkg-1.9.4_1。然后就不能用了。提示 /usr/local/lib/libpkg.so.3: Undefined symbol "openat" pkg命令不能用了。好像是内核版本太低了。就找了一下怎么解决。 有个pkg-static命令可以使用,,然后/var/cache/pkg里边缓存的包。执行命令: pkg-static install -f /var/cache/pkg/pkg-1.9.3.txz 强制换低版本的pkg。然后就好了。。没有这个包可以去freebsd官网下一个。

Continue

先看看上次没看完的client的初始化。 NewAPIClientFromFlags里 getServerHost(opts.Hosts, opts.TLSOptions),如果参数有指定用参数的,如果没指定用os.Getenv("DOCKER_HOST"). 设置customHeaders,环境变量如果有设置DOCKER_API_VERSION,设置api版本 newHTTPClient(host, opts.TLSOptions)返回一个http.client client.NewClient(host, verStr, httpClient, customHeaders)初始化一个新的Client对象,Client是啥, client/interface_stable.go package client // APIClient is an interface that clients that talk with a docker server must implement. type APIClient interface { CommonAPIClient apiClientExperimental } // Ensure that Client always implements APIClient. var _ APIClient = &Client{} APIClient是个接口类型,看了一下包含了好多函数,应该是所有命令集中都是调的这里的。Client就是一个APIClient接口类型的实现。这样写一句应该能保证,不然编译不过,哈哈 会玩。。 client的命令都是在上一篇的AddCommands里边集中添加,对应各个目录里边的cmd.go里的NewCommand方法进行添加。 client.Ping( 在client/ping.go里, 先req, err := cli.buildRequest("GET", fmt.Sprintf("%s/_ping", cli.basePath), nil, nil),构造请求 serverResp, err := cli.doRequest(ctx, req),发送请求返回结果,都在request.go里边,普通的http请求。 然后ping.APIVersion和ping.Experimental都是根据返回的header来判断的,Experimental具体干啥的还不清楚 client.UpdateClientVersion,这个仅仅是改了一下client的版本,可能请求是带上这个版本,服务端会根据这个版本进行不同操作返回吧。还不确定。cli.version = v 这个样整个dockerCli就初始化完了。核心就是那个Client,各种请求的定义都在里边。 再看看具体命令的执行,看个docker info命令,感觉这个应该简单点。 system.NewSystemCommand(dockerCli), system.NewVersionCommand(dockerCli), 正好还有个version,先看看这个。在runVersion(里边, ctx := context.Background() 先创建一个空context,versionTemplate 格式化模板,如果提供opts.format参数,就使用提供的模板。上边有这个操作 APIVersion := dockerCli.Client().ClientVersion() 这里找了一下Client()返回dockerCli.client就是上边提到的初始化的那个,client.APIClient类型的 ClientVersion() 在client/client.go里边定义:func (cli *Client) ClientVersion() string返回Client .version字段。也和之前的一样 下边就是版本不统一,api版本低的话会让cli的版本也低,然后会跟随打印出来。api版本高的话,可能兼容的,这个也不确定。 dockerCli.Client().ServerVersion(ctx)然后请求server的版本。cli.get(ctx, "/version", nil, nil)走接口请求. 最后就是渲染模板,进行打印。 types 都在api/types定义的。可能会公用到吧,不太清楚。 总的来说就是client解析参数,然后找到对应的处理方法,发送请求给server,然后server返回。这个和官方提供的api是用的一样的。我记得之前搭建docker环境的时候踩过一个坑,配置api的访问接口的时候,把socket给去掉了,只留个ip:port的,本地命令就没法执行了。本地默认好像走的socket文件的。 其他client端的命令就不看了 ,应该都是一样的。下边就看看server的。

Continue

先看docker/cmd/docker/docker.go 主要就三行 dockerCli := command.NewDockerCli(stdin, stdout, stderr) cmd := newDockerCommand(dockerCli) if err := cmd.Execute(); err != nil { NewDockerCli( 在docker/cli/command/cli.go里返回一个DockerCli实例 type DockerCli struct { configFile *configfile.ConfigFile in *InStream out *OutStream err io.Writer keyFile string client client.APIClient hasExperimental bool defaultVersion string } 设置一些client都用的些东西。初始化了in,out,err,其他字段先不管,按流程看。 newDockerCommand 先实例化一个ClientOptions, type ClientOptions struct { Common *CommonOptions ConfigDir string Version bool } 然后用了一个cobra库,应该就是管理命令行参数的。 PersistentPreRunE里边,一些参数设置。 daemon启动废弃了,所以就不设置这些参数啥的了。 opts.Common.SetDefaultOptions(flags)设置CommonOptions的一些默认参数. dockerPreRun(opts)里opts.ConfigDir可以通过设置配置文件路径,这个是默认的:configDir = os.Getenv("DOCKER_CONFIG"), 参数肯定优先级高,哈哈,SetDir会替换成参数里的。config参数的定义在newDockerCommand的最下边。 func Enable() { os.Setenv("DEBUG", "1") logrus.SetLevel(logrus.DebugLevel) } 根据参数是否开启debug dockerCli.Initialize(opts)进行dockerCli的初始化,之前只是初始化输入输出,还有其他字段要初始化。 LoadDefaultConfigFile初始化configFile字段,看名字基本就知道啥功能了。文件路径是环境变量定义的configDir = os.Getenv("DOCKER_CONFIG"),怎么load的就不看了.再往下好像是证书相关的配置需要设置参数。 NewAPIClientFromFlags(opts.Common, cli.configFile)是初始化dockerCli的client字段。具体怎么初始化的,这个等后边看。内容挺多的 cli.defaultVersion初始化另一个字段,就是client的版本.keyFile初始化, ping操作主要是获取api的版本,如果ping.APIVersion为空,就默认1.24,是1。24之前不支持这个字段,因为现在肯定大于1.24了。HasExperimental初始化 如果api版本小于客户端版本,应该是不能使用,需要把客户端版本降级。UpdateClientVersion操作。这个也后边集中分析一下。 return isSupported(cmd, dockerCli.Client().ClientVersion(), dockerCli.HasExperimental()) HasExperimental这个也是ping的时候返回的,这里主要还是版本判断,过了,cobra参数也看不太懂。 opts.Common.InstallFlags(flags)设置了一些参数,一些指定host,key,版本啥参数.与client连接server有关的设置。 cmd.AddCommand(newDaemonCommand()) 之前好像启动client和daemon是一个文件,现在分开了。这里看的是client的代码,使用之前的daemon参数进行启动的时候,提示新版本已经分开了。 commands.AddCommands(cmd, dockerCli) docker/cli/commands/commands.go 这里就是添加命令参数了。注释分类挺清楚的,分别在不同文件里边。 这个后边再细看,都差不多,命令定义都在command目录下 cmd.Execute(); 这个应该就是cobra一切设置完了 开始监听参数并执行相应方法了。

Continue

这个本用了有半年了,mac pro最低配置的,感觉最紧的就是硬盘了。然后再是内存,开几个程序内存基本就满了。别的都挺好。 本来一直没升级,想清理空间的时候网上搜到一个图,后来发现是新版sierra里才有的硬盘分析工具。于是升级了系统版本。 新系统有个siri的功能,连看没看直接没启用,,因为我从来没用过GarageBand,感觉以后也不会用上,就也卸载了 Macintosh HD/Applications/GarageBand.app (1.16GB) Macintosh HD/Library/Application Support/GarageBand (995MB) Macintosh HD/Library/Application Support/Logic (880MB) Macintosh HD/Library/Audio/Apple Loops (up to 10GB)*xx 删掉这几个目录就可以了。使用工具邮件也清理了一下,瞬间释放好多硬盘空间。 等周末再把 不看的pdf移动到nas上 ,空间就足够搞别的了。应用程序装了几个ide 有点消耗空间,还不想卸载,,

Continue

直接从makefile入手找到hack/make.sh,具体怎么编译的不看,只找入口. 看make.sh要编译的东西主要应该就看俩就行了,一个是clien,一个是daemon。 binary-client binary-daemon dynbinary test-unit test-integration-cli test-docker-py cross tgz 其他一些测试用的,不管,还有一些不知道。以后再说。 然后往下翻发现都在hack/make/目录里边对应的文件。 俩文件样子差不多,binary-client 二进制名为docker ,binary-daemon为dockerd。源码目录分别对应 docker/cmd/docker,docker/cmd/dockerd 搞定,后边再接着看。

Continue

一直在调试ios的react-native的程序,好久没在Android下编译过,今天搞了一下。编译通过了,程序启动报了个错误“Unfortunately, app has stopped” adb logcat 能看到log。github有解决方式 编辑android/app/src/main/AndroidManifest.xml文件 application标签里加个属性android:name=".MainApplication" 然后就好了

Continue

这俩软件直接brew install安装的。 opam需要配置 opam init 初始化opam目录,~/.opam .bash_profile里添加. ~/.opam/opam-init/init.sh > /dev/null 2> /dev/null || true 设置一些环境变量。 vim ~/.ocamlinit 添加 let () = try Topdirs.dir_directory (Sys.getenv "OCAML_TOPLEVEL_PATH") with Not_found -> () ;; 这些配置提示,在执行opam init 的时候会显示。 opam switch可以查看已经安装的版本编译器,并可以切换 $ opam switch 4.01.0 $ eval `opam config env` 安装utop opam install core utop 然后会装特么的一堆包。 再次配置.ocamlinit 就是初始导入,以后启动解析器的时候就不用导入了 #use "topfind";; #thread;; #camlp4o;; #require "core.top";; #require "core.syntax";; open Core.Std;; 可以用utop愉快的玩耍了

Continue