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完结撒花,设置了一下目录,用户的映射
Read more...
Archive for 算法-编程
Docker源码阅读4-daemon流程
东西太多了,大体过了一下,感觉会少了很多东西。有一些三方库,也没去看库怎么用。就看函数名大体猜一下功能。
完全就是从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是干嘛的
Read more...
mac上Corona安装调试
哈哈,找了个跨平台的游戏框架玩玩。
在mac平台上安装试了一下。下载需要注册,第一次启动也需要填注册的账号,所以还是注册了。
安装完启动输入账号,完成后创建一个项目。直接点击是使用的手机模拟器启动的。
官方给出的命令启动方法,-no-console YES是不显示debug信息。
"/Applications/CoronaSDK/Corona Simulator.app/Contents/MacOS/Corona Simulator" ~/CoronaApps/MyApp
作为桌面软件启动的时候,还是要先开模拟器编译通过后,菜单选择File → Build → macOS.填填选项。选择 Open application编译完启动,或者编译完手动启动也行。
Read more...
Docker源码阅读3-client命令
先看看上次没看完的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的。
Read more...
Docker学习源码阅读2-client流程阅读
先看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一切设置完了 开始监听参数并执行相应方法了。
Read more...
Docker学习源码阅读1-入口分析
直接从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
搞定,后边再接着看。
Read more...
react-native android报错“Unfortunately, app has stopped”
一直在调试ios的react-native的程序,好久没在Android下编译过,今天搞了一下。编译通过了,程序启动报了个错误“Unfortunately, app has stopped”
adb logcat 能看到log。github有解决方式
编辑android/app/src/main/AndroidManifest.xml文件
application标签里加个属性android:name=".MainApplication"
然后就好了
Read more...
mac安装ocaml和opam
这俩软件直接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愉快的玩耍了
Read more...
mac os安装f#
安装管网提示一步步安装的。还有个mono的东西,没用。
brew update
brew install openssl
第二部下载安装包,点击安装。安装完目录添加到path。
创建一个hello world例子工程
Read more...
mkdir hwapp
cd hwapp
dotnet new --lang f#
运行例子
dotnet restore
dotnet run
就输出f#版的hello world了
使用druid解析sql
那些开源的都不太靠谱,同事推荐这个druid解析sql。试了一下确实给力。
打包方法:
git clone https://github.com/alibaba/druid.git
mvn install -Dmaven.javadoc.skip=true -Dmaven.test.skip=true
会安装到.m2目录,copy一个项目用
target/druid-1.0.27-SNAPSHOT-sources.jar
示例代码:
Read more...
import java.util.*;
import com.alibaba.druid.stat.TableStat;
import com.alibaba.druid.sql.ast.SQLStatement;
import com.alibaba.druid.sql.dialect.mysql.parser.MySqlStatementParser;
import com.alibaba.druid.sql.dialect.mysql.visitor.MySqlSchemaStatVisitor;
import py4j.GatewayServer;
public class SQLParser {
public static List get_tables(String sql){
MySqlStatementParser parser = new MySqlStatementParser(sql);
List statementList = parser.parseStatementList();
SQLStatement statemen = statementList.get(0);
MySqlSchemaStatVisitor visitor = new MySqlSchemaStatVisitor();
statemen.accept(visitor);
Map result = visitor.getTables();
System.out.println("Tables : " + result);
List list = new ArrayList<>();
for ( TableStat.Name name : result.keySet() ) {
System.out.println( name );
list.add(name.getName());
}
return list;
}
public static void main(String[] args){
GatewayServer gatewayServer = new GatewayServer(new SQLParser());
gatewayServer.start();
System.out.println("Gateway Server Started");
}
}
打包命令:
javac -cp .:./py4j0.10.4.jar:./druid-1.0.27-SNAPSHOT.jar:$CLASSPATH SQLParser.java
java -cp .:./py4j0.10.4.jar:./druid-1.0.27-SNAPSHOT.jar:$CLASSPATH SQLParser