Thanks to visit codestin.com
Credit goes to github.com

Skip to content
This repository was archived by the owner on Feb 24, 2020. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#### New features and UX changes

- Add pod creation and start times to `rkt list` and `rkt status` ([#2030](https://github.com/coreos/rkt/pull/2030)). See [`rkt list`](https://github.com/coreos/rkt/blob/master/Documentation/subcommands/list.md) and [`rkt status`](https://github.com/coreos/rkt/blob/master/Documentation/subcommands/status.md) documentation.
- The DNS configuration can now be passed to the pod via the command line ([#2040](https://github.com/coreos/rkt/pull/2040)). See [`DNS support`](https://github.com/coreos/rkt/blob/master/Documentation/networking.md#dns-support) documentation.

## v0.16.0

Expand Down
25 changes: 25 additions & 0 deletions Documentation/networking.md
Original file line number Diff line number Diff line change
Expand Up @@ -341,3 +341,28 @@ rkt run --net="all,net1:IP=1.2.3.4" --net="net2:IP=1.2.4.5" pod.aci

This is not documented yet.
Please follow [this issue on CNI](https://github.com/appc/cni/issues/56) to track the progress of the documentation.

## DNS support

rkt can automatically prepare `/etc/resolv.conf` for the apps in the pod. The simplest configuration is:

```bash
rkt run --dns=8.8.8.8 pod.aci
```

Other parameters can be given:

```bash
rkt run --dns=8.8.8.8 --dns=8.8.4.4 --dns-search=foo.com --dns-opt=debug pod.aci
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should mention that only 3 nameservers will be considered

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above.

```

This will generate the following `/etc/resolv.conf` for the applications:

```
# Generated by rkt

search foo.com
nameserver 8.8.8.8
nameserver 8.8.4.4
options debug
```
28 changes: 28 additions & 0 deletions rkt/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,9 @@ End the image arguments with a lone "---" to resume argument parsing.`,
flagInheritEnv bool
flagExplicitEnv envMap
flagInteractive bool
flagDNS flagStringList
flagDNSSearch flagStringList
flagDNSOpt flagStringList
flagNoOverlay bool
flagStoreOnly bool
flagNoStore bool
Expand All @@ -76,6 +79,9 @@ func init() {
cmdRun.Flags().BoolVar(&flagPrivateUsers, "private-users", false, "Run within user namespaces (experimental).")
cmdRun.Flags().Var(&flagExplicitEnv, "set-env", "an environment variable to set for apps in the form name=value")
cmdRun.Flags().BoolVar(&flagInteractive, "interactive", false, "run pod interactively. If true, only one image may be supplied.")
cmdRun.Flags().Var(&flagDNS, "dns", "name servers to write in /etc/resolv.conf")
cmdRun.Flags().Var(&flagDNSSearch, "dns-search", "DNS search domains to write in /etc/resolv.conf")
cmdRun.Flags().Var(&flagDNSOpt, "dns-opt", "DNS options to write in /etc/resolv.conf")
cmdRun.Flags().BoolVar(&flagStoreOnly, "store-only", false, "use only available images in the store (do not discover or download from remote URLs)")
cmdRun.Flags().BoolVar(&flagNoStore, "no-store", false, "fetch images ignoring the local store")
cmdRun.Flags().StringVar(&flagPodManifest, "pod-manifest", "", "the path to the pod manifest. If it's non-empty, then only '--net', '--no-overlay' and '--interactive' will have effects")
Expand All @@ -91,6 +97,9 @@ func init() {
cmdRun.Flags().Var((*appCPULimit)(&rktApps), "cpu", "cpu limit for the preceding image (example: '--cpu=500m')")

flagPorts = portList{}
flagDNS = flagStringList{}
flagDNSSearch = flagStringList{}
flagDNSOpt = flagStringList{}

// Disable interspersed flags to stop parsing after the first non flag
// argument. All the subsequent parsing will be done by parseApps.
Expand Down Expand Up @@ -271,6 +280,9 @@ func runRun(cmd *cobra.Command, args []string) (exit int) {
Net: flagNet,
LockFd: lfd,
Interactive: flagInteractive,
DNS: flagDNS,
DNSSearch: flagDNSSearch,
DNSOpt: flagDNSOpt,
MDSRegister: flagMDSRegister,
LocalConfig: globalFlags.LocalConfigDir,
RktGid: rktgid,
Expand Down Expand Up @@ -328,6 +340,22 @@ func (pl *portList) Type() string {
return "portList"
}

// flagStringList implements the flag.Value interface to contain a set of strings
type flagStringList []string
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@krnowak where is the preferred place to add this new type?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we have a good place to put new types used in several, but not all commands. But often rkt.go serves as a dumpster for this kind of stuff. ;)

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, this is quite generic, so rkt.go it is.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe I wrote a similar thing somewhere before...

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's here - https://github.com/coreos/rkt/blob/master/tools/common/util.go#L24

Maybe we should move this thing elsewhere.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

However, rkt/run.go already has some flag types: envMap, portList. Should I still move it to rkt.go which does not have any flag type yet?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just keep it here then. We can later move this stuff in to a separate go file.


func (dns *flagStringList) Set(s string) error {
*dns = append(*dns, s)
return nil
}

func (dns *flagStringList) String() string {
return strings.Join(*dns, " ")
}

func (dns *flagStringList) Type() string {
return "flagStringList"
}

// envMap implements the flag.Value interface to contain a set of name=value mappings
type envMap struct {
mapping map[string]string
Expand Down
6 changes: 6 additions & 0 deletions rkt/run_prepared.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ func init() {

cmdRunPrepared.Flags().Var(&flagNet, "net", "configure the pod's networking. optionally pass a list of user-configured networks to load and arguments to pass to them. syntax: --net[=n[:args]][,]")
cmdRunPrepared.Flags().Lookup("net").NoOptDefVal = "default"
cmdRunPrepared.Flags().Var(&flagDNS, "dns", "name servers to write in /etc/resolv.conf")
cmdRunPrepared.Flags().Var(&flagDNSSearch, "dns-search", "DNS search domains to write in /etc/resolv.conf")
cmdRunPrepared.Flags().Var(&flagDNSOpt, "dns-opt", "DNS options to write in /etc/resolv.conf")
cmdRunPrepared.Flags().BoolVar(&flagInteractive, "interactive", false, "the pod is interactive")
cmdRunPrepared.Flags().BoolVar(&flagMDSRegister, "mds-register", false, "register pod with metadata service")
}
Expand Down Expand Up @@ -123,6 +126,9 @@ func runRunPrepared(cmd *cobra.Command, args []string) (exit int) {
Net: flagNet,
LockFd: lfd,
Interactive: flagInteractive,
DNS: flagDNS,
DNSSearch: flagDNSSearch,
DNSOpt: flagDNSOpt,
MDSRegister: flagMDSRegister,
Apps: apps,
RktGid: rktgid,
Expand Down
34 changes: 34 additions & 0 deletions stage0/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import (
"fmt"
"io/ioutil"
"log"
"net"
"os"
"path"
"path/filepath"
Expand Down Expand Up @@ -87,6 +88,9 @@ type RunConfig struct {
Apps schema.AppList // applications (prepare gets them via Apps)
LocalConfig string // Path to local configuration
RktGid int // group id of the 'rkt' group, -1 if there's no rkt group.
DNS []string // DNS name servers to write in /etc/resolv.conf
DNSSearch []string // DNS search domains to write in /etc/resolv.conf
DNSOpt []string // DNS options to write in /etc/resolv.conf
}

// configuration shared by both Run and Prepare
Expand Down Expand Up @@ -379,6 +383,32 @@ func preparedWithPrivateUsers(dir string) (string, error) {
return string(bytes), nil
}

func addResolvConf(cfg RunConfig, rootfs string) {
content := "# Generated by rkt\n\n"
if len(cfg.DNSSearch) > 0 {
content += fmt.Sprintf("search %s\n", strings.Join(cfg.DNSSearch, " "))
}
for _, server := range cfg.DNS {
// skip empty entries
if server == "" {
continue
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might be a good idea to check if server is a valid IP address here

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok

// comment invalid entries
if net.ParseIP(server) == nil {
content += "# "
}
content += "nameserver " + server + "\n"
}
if len(cfg.DNSOpt) > 0 {
content += fmt.Sprintf("options %s\n", strings.Join(cfg.DNSOpt, " "))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Validate DNS options maybe? There are only a few of those, validating will give better UX with a constant overhead

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But rkt would need to keep the list of options in sync with the glibc options when new options are added. It does not happen that often but still. The last one to be added seems to be use-vc documented in man-pages in 2015.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again, I find this very restricting as it depends on the implementation. I would be very annoyed if I were to develop a new DNS option and couldn't test it in rkt.

}
content += "\n"

if err := ioutil.WriteFile(filepath.Join(rootfs, "etc/rkt-resolv.conf"), []byte(content), 0644); err != nil {
log.Fatalf("error writing /etc/rkt-resolv.conf: %v\n", err)
}
}

// Run mounts the right overlay filesystems and actually runs the prepared
// pod by exec()ing the stage1 init inside the pod filesystem.
func Run(cfg RunConfig, dir string, dataDir string) {
Expand Down Expand Up @@ -406,6 +436,10 @@ func Run(cfg RunConfig, dir string, dataDir string) {

destRootfs := common.Stage1RootfsPath(dir)

if len(cfg.DNS) > 0 || len(cfg.DNSSearch) > 0 || len(cfg.DNSOpt) > 0 {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

libc does not recognize more than 3 DNS servers. We should error out if more than 3 are supplied.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not our responsibility to do this nor can't we be certain that the application inside uses libc's resolver.

addResolvConf(cfg, destRootfs)
}

if err := os.Setenv(common.EnvLockFd, fmt.Sprintf("%v", cfg.LockFd)); err != nil {
log.Fatalf("setting lock fd environment: %v", err)
}
Expand Down
29 changes: 26 additions & 3 deletions stage1/prepare-app/prepare-app.c
Original file line number Diff line number Diff line change
Expand Up @@ -147,12 +147,15 @@ int main(int argc, char *argv[])
"/dev/console",
NULL
};
static const mount_point mount_table[] = {
static const mount_point dirs_mount_table[] = {
{ "/proc", "/proc", "bind", NULL, MS_BIND|MS_REC },
{ "/sys", "/sys", "bind", NULL, MS_BIND|MS_REC },
{ "/dev/shm", "/dev/shm", "bind", NULL, MS_BIND },
{ "/dev/pts", "/dev/pts", "bind", NULL, MS_BIND },
};
static const mount_point files_mount_table[] = {
{ "/etc/rkt-resolv.conf", "/etc/resolv.conf", "bind", NULL, MS_BIND },
};
const char *root;
int rootfd;
char to[4096];
Expand Down Expand Up @@ -243,8 +246,8 @@ int main(int argc, char *argv[])
}

/* Bind mount directories */
for (i = 0; i < nelems(mount_table); i++) {
const mount_point *mnt = &mount_table[i];
for (i = 0; i < nelems(dirs_mount_table); i++) {
const mount_point *mnt = &dirs_mount_table[i];

exit_if(snprintf(to, sizeof(to), "%s/%s", root, mnt->target) >= sizeof(to),
"Path too long: \"%s\"", to);
Expand All @@ -253,6 +256,26 @@ int main(int argc, char *argv[])
"Mounting \"%s\" on \"%s\" failed", mnt->source, to);
}

/* Bind mount files, if the source exists */
for (i = 0; i < nelems(files_mount_table); i++) {
const mount_point *mnt = &files_mount_table[i];
int fd;

exit_if(snprintf(to, sizeof(to), "%s/%s", root, mnt->target) >= sizeof(to),
"Path too long: \"%s\"", to);
if (access(mnt->source, F_OK) != 0)
continue;
if (access(to, F_OK) != 0) {
pexit_if((fd = creat(to, 0644)) == -1,
"Cannot create file: \"%s\"", to);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we get more information in case of an error? Is there an implicit ERRNO parser here?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, the p of pexit_if means it will use strerror(errno) at the end of the error message.

pexit_if(close(fd) == -1,
"Cannot close file: \"%s\"", to);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

see above

}
pexit_if(mount(mnt->source, to, mnt->type,
mnt->flags, mnt->options) == -1,
"Mounting \"%s\" on \"%s\" failed", mnt->source, to);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

see above

}

/* /dev/ptmx -> /dev/pts/ptmx */
exit_if(snprintf(to, sizeof(to), "%s/dev/ptmx", root) >= sizeof(to),
"Path too long: \"%s\"", to);
Expand Down
67 changes: 67 additions & 0 deletions tests/rkt_dns_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
// Copyright 2016 The rkt Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package main

import (
"fmt"
"os"
"testing"

"github.com/coreos/rkt/tests/testutils"
)

// TestDNS is checking how rkt fills /etc/resolv.conf
func TestDNS(t *testing.T) {
imageFile := patchTestACI("rkt-inspect-exit.aci", "--exec=/inspect --print-msg=Hello --read-file")
defer os.Remove(imageFile)
ctx := testutils.NewRktRunCtx()
defer ctx.Cleanup()

for _, tt := range []struct {
paramDNS string
expectedLine string
}{
{
paramDNS: "",
expectedLine: "Cannot read file",
},
{
paramDNS: "--dns=8.8.4.4",
expectedLine: "nameserver 8.8.4.4",
},
{
paramDNS: "--dns=8.8.8.8 --dns=8.8.4.4",
expectedLine: "nameserver 8.8.8.8",
},
{
paramDNS: "--dns=8.8.8.8 --dns=8.8.4.4 --dns-search=search.com --dns-opt=debug",
expectedLine: "nameserver 8.8.4.4",
},
{
paramDNS: "--dns-search=foo.com --dns-search=bar.com",
expectedLine: "search foo.com bar.com",
},
{
paramDNS: "--dns-opt=debug --dns-opt=use-vc --dns-opt=rotate",
expectedLine: "options debug use-vc rotate",
},
} {

rktCmd := fmt.Sprintf(`%s --insecure-options=image run --set-env=FILE=/etc/resolv.conf %s %s`,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just me being curious: any reason why you didn't put --insecure-options=image run --set-env=FILE=/etc/resolv.conf to line 27?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did that by mistake at first but it was not working: line 27 has the parameters to actool patch-manifest. Line 57 has the parameters for rkt. --insecure-options and --set-env should be arguments to rkt and not actool.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Obviously I would've made the same mistake at first ;-)

ctx.Cmd(), tt.paramDNS, imageFile)
t.Logf("%s\n", rktCmd)
runRktAndCheckOutput(t, rktCmd, tt.expectedLine, false)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These tests should be improved in the future to match against the whole file instead of lines. That way we can ensure that the order is deterministic which might matter for some DNS implementations.

}
}