Merge pull request #4509 from dokku/4477-initial-network

Add ability to specify initial network
This commit is contained in:
Jose Diaz-Gonzalez
2021-07-09 22:06:28 -04:00
committed by GitHub
13 changed files with 319 additions and 64 deletions

View File

@@ -15,7 +15,7 @@ insert_final_newline = true
indent_style = tab
indent_size = 4
[*.go]
[*.{go,mod}]
insert_final_newline = true
indent_style = tab
indent_size = 4

View File

@@ -0,0 +1,5 @@
# 0.25.0 Migration Guide
## Changes
- The network plugin can now set an `initial-network` for all containers on creation. This is a replacement for specifying the `--network` flag via the `docker-options` plugin. Please see the [network documentation](/docs/networking/network.md#attaching-an-app-to-a-network) for more information.

View File

@@ -127,7 +127,7 @@ dokku network:info test-network
> New as of 0.20.0, Requires Docker 1.21+
Apps will default to being associated with the `bridge` network, but can be attached to `attachable` networks by changing the `attach-post-create` or `attach-post-deploy` network properties when using the [docker-local scheduler](/docs/advanced-usage/schedulers/docker-local.md). A change in these values will require an app deploy or rebuild.
Apps will default to being associated with the default `bridge` network or a network specified by the `initial-network` network property. Additionally, an app can be attached to `attachable` networks by changing the `attach-post-create` or `attach-post-deploy` network properties when using the [docker-local scheduler](/docs/advanced-usage/schedulers/docker-local.md). A change in these values will require an app deploy or rebuild.
```shell
# associates the network after a container is created but before it is started
@@ -135,6 +135,9 @@ dokku network:set node-js-app attach-post-create test-network
# associates the network after the deploy is successful but before the proxy is updated
dokku network:set node-js-app attach-post-deploy other-test-network
# associates the network at container creation
dokku network:set node-js-app initial-network global-network
```
Setting the `attach` network property to an empty value will de-associate the container with the network.
@@ -142,6 +145,23 @@ Setting the `attach` network property to an empty value will de-associate the co
```shell
dokku network:set node-js-app attach-post-create
dokku network:set node-js-app attach-post-deploy
dokku network:set node-js-app initial-network
```
The network properties can also be set globally. The global default is emty string, and the global value is used when no app-specific value is set.
```shell
dokku network:set --global attach-post-create global-create-network
dokku network:set --global attach-post-deploy global-deploy-network
dokku network:set --global initial-network global-network
```
The default value may be set by passing an empty value for the option.
```shell
dokku network:set --global attach-post-create
dokku network:set --global attach-post-deploy
dokku network:set --global initial-network
```
#### Network Aliases
@@ -162,7 +182,7 @@ Dockerfile-based applications may listen on other ports. For more information on
#### Specifying a custom TLD
When attaching applications to networks, a custom TLD can be specified via the `network:set` command. This TLD is suffixed to the network alias for the application/process-type combination for _all_ networks to which the application is attached, and cannot be customized per network.
When attaching applications to networks, a custom TLD can be specified via the `network:set` command. This TLD is suffixed to the network alias for the application/process-type combination for _all_ networks to which the application is attached, and cannot be customized per network. The default value is an empty string.
To specify a TLD of `svc.cluster.local` for your application, run the following command:
@@ -179,6 +199,24 @@ node-js-app.web.svc.cluster.local
Note that this has no impact on container port handling, and users must still specify the container port when making internal network requests.
The default value may be set by passing an empty value for the option:
```shell
dokku network:set node-js-app tld
```
The `tld` property can also be set globally. The global default is emty string, and the global value is used when no app-specific value is set.
```shell
dokku network:set --global tld svc.cluster.local
```
The default value may be set by passing an empty value for the option.
```shell
dokku network:set --global tld
```
#### When to attach containers to a network
Containers can be attached to a network for a variety of reasons:
@@ -203,8 +241,17 @@ Whatever the reason, the semantics of the two network hooks are important and ar
- Container state on attach: `running`
- Use case: When another container on the network needs to access _this_ container.
- Example: A background process needs to communicate with the web process exposed by this container.
- `initial-network`:
- Phase it applies to:
- `build`: Intermediate containers created during the build process.
- `deploy`: Deployed app containers.
- `run`: Containers created by the `run` command.
- Container state on attach: `created`
- Use case: When another container on the network is already running and needed by this container.
- Example: A key-value store exposing itself to all your apps may be on the `initial-network`.
> Warning: If the attachment fails at this stage, this may result in your application failing to respond to proxied requests once older containers are removed.
> Warning: If the attachment fails during the `running` container state, this may result in your application failing to respond to proxied requests once older containers are removed.
### Rebuilding network settings
@@ -278,6 +325,18 @@ CONTAINER ID IMAGE COMMAND CREATED
d6499edb0edb dokku/node-js-app:latest "/bin/bash -c '/star About a minute ago Up About a minute 0.0.0.0:49153->5000/tcp node-js-app.web.1
```
The `bind-all-interfaces` property can also be set globally. The global default is `false`, and the global value is used when no app-specific value is set.
```shell
dokku network:set --global bind-all-interfaces true
```
The default value may be set by passing an empty value for the option.
```shell
dokku network:set --global bind-all-interfaces
```
### Displaying network reports for an app
You can get a report about the app's network status using the `network:report` command:
@@ -288,14 +347,56 @@ dokku network:report
```
=====> node-js-app network information
Network bind all interfaces: false
Network listeners: 172.17.0.1:5000
Network attach post create:
Network attach post deploy:
Network bind all interfaces: false
Network computed attach post create:
Network computed attach post deploy:
Network computed bind all interfaces:false
Network computed initial network:
Network computed tld:
Network global attach post create:
Network global attach post deploy:
Network global bind all interfaces:false
Network global initial network:
Network global tld:
Network initial network:
Network tld:
Network web listeners: 172.17.0.1:5000
=====> python-sample network information
Network bind all interfaces: false
Network listeners: 172.17.0.2:5000
Network attach post create:
Network attach post deploy:
Network bind all interfaces: false
Network computed attach post create:
Network computed attach post deploy:
Network computed bind all interfaces:false
Network computed initial network:
Network computed tld:
Network global attach post create:
Network global attach post deploy:
Network global bind all interfaces:false
Network global initial network:
Network global tld:
Network initial network:
Network tld:
Network web listeners: 172.17.0.2:5000
=====> ruby-sample network information
Network bind all interfaces: true
Network listeners:
Network attach post create:
Network attach post deploy:
Network bind all interfaces: false
Network computed attach post create:
Network computed attach post deploy:
Network computed bind all interfaces:false
Network computed initial network:
Network computed tld:
Network global attach post create:
Network global attach post deploy:
Network global bind all interfaces:false
Network global initial network:
Network global tld:
Network initial network:
Network tld:
Network web listeners:
```
You can run the command for a specific app also.
@@ -306,8 +407,22 @@ dokku network:report node-js-app
```
=====> node-js-app network information
Network bind all interfaces: false
Network listeners: 172.17.0.1:5000
Network attach post create:
Network attach post deploy:
Network bind all interfaces: false
Network computed attach post create:
Network computed attach post deploy:
Network computed bind all interfaces:false
Network computed initial network:
Network computed tld:
Network global attach post create:
Network global attach post deploy:
Network global bind all interfaces:false
Network global initial network:
Network global tld:
Network initial network:
Network tld:
Network web listeners: 172.17.0.1:5000
```
You can pass flags which will output only the value of the specific information you want. For example:

View File

@@ -1 +1,6 @@
/prop
/common
/core-post-deploy
/install
/post-delete
/triggers

View File

@@ -7,3 +7,6 @@
/install
/post-*
/report
/docker-args-process-build
/docker-args-process-deploy
/docker-args-process-run

View File

@@ -1,5 +1,5 @@
SUBCOMMANDS = subcommands/create subcommands/destroy subcommands/exists subcommands/info subcommands/list subcommands/rebuild subcommands/rebuildall subcommands/report subcommands/set
TRIGGERS = triggers/core-post-deploy triggers/install triggers/network-build-config triggers/network-compute-ports triggers/network-config-exists triggers/network-get-ipaddr triggers/network-get-listeners triggers/network-get-port triggers/network-get-property triggers/network-write-ipaddr triggers/network-write-port triggers/post-app-clone-setup triggers/post-app-rename-setup triggers/post-container-create triggers/post-create triggers/post-delete triggers/report
TRIGGERS = triggers/core-post-deploy triggers/docker-args-process-build triggers/docker-args-process-deploy triggers/docker-args-process-run triggers/install triggers/network-build-config triggers/network-compute-ports triggers/network-config-exists triggers/network-get-ipaddr triggers/network-get-listeners triggers/network-get-port triggers/network-get-property triggers/network-write-ipaddr triggers/network-write-port triggers/post-app-clone-setup triggers/post-app-rename-setup triggers/post-container-create triggers/post-create triggers/post-delete triggers/report
BUILD = commands subcommands triggers
PLUGIN_NAME = network

View File

@@ -20,9 +20,7 @@ func attachAppToNetwork(containerID string, networkName string, appName string,
}
if phase == "deploy" {
property := "tld"
defaultValue := GetDefaultValue(property)
tld := common.PropertyGetDefault("network", appName, property, defaultValue)
tld := reportComputedTld(appName)
networkAlias := fmt.Sprintf("%v.%v", appName, processType)
if tld != "" {
@@ -62,14 +60,13 @@ func isConflictingPropertyValue(appName string, property string, value string) b
return false
}
otherProperty := "attach-post-create"
if property == otherProperty {
otherProperty = "attach-post-deploy"
otherValue := ""
if property == "attach-post-create" {
otherValue = reportComputedAttachPostDeploy(appName)
} else {
otherValue = reportComputedAttachPostCreate(appName)
}
defaultValue := GetDefaultValue(otherProperty)
otherValue := common.PropertyGetDefault("network", appName, otherProperty, defaultValue)
return value == otherValue
}

View File

@@ -17,14 +17,21 @@ import (
var (
// DefaultProperties is a map of all valid network properties with corresponding default property values
DefaultProperties = map[string]string{
"bind-all-interfaces": "false",
"bind-all-interfaces": "",
"attach-post-create": "",
"attach-post-deploy": "",
"initial-network": "",
"tld": "",
}
// GlobalProperties is a map of all valid global network properties
GlobalProperties = map[string]bool{}
GlobalProperties = map[string]bool{
"bind-all-interfaces": true,
"attach-post-create": true,
"attach-post-deploy": true,
"initial-network": true,
"tld": true,
}
)
// BuildConfig builds network config files
@@ -105,9 +112,14 @@ func GetContainerIpaddress(appName, processType, containerID string) (ipAddr str
}
}
b, err := common.DockerInspect(containerID, "{{.NetworkSettings.Networks.bridge.IPAddress}}")
initialNetwork := reportComputedInitialNetwork(appName)
if initialNetwork == "" {
initialNetwork = "bridge"
}
b, err := common.DockerInspect(containerID, fmt.Sprintf("{{ $network := index .NetworkSettings.Networks \"%s\" }}{{ $network.IPAddress}}", initialNetwork))
if err != nil || len(b) == 0 {
// docker < 1.9 compatibility
// Deprecated: docker < 1.9 compatibility
b, err = common.DockerInspect(containerID, "{{ .NetworkSettings.IPAddress }}")
}
@@ -151,15 +163,6 @@ func GetContainerPort(appName, processType string, containerID string, isHerokui
return
}
// GetDefaultValue returns the default value for a given property
func GetDefaultValue(property string) (value string) {
value, ok := DefaultProperties[property]
if ok {
return
}
return
}
// GetListeners returns a string array of app listeners
func GetListeners(appName string, processType string) []string {
appRoot := common.AppRoot(appName)

View File

@@ -1,12 +0,0 @@
package network
import (
"testing"
. "github.com/onsi/gomega"
)
func TestNetworkGetDefaultValue(t *testing.T) {
RegisterTestingT(t)
Expect(GetDefaultValue("bind-all-interfaces")).To(Equal("false"))
}

View File

@@ -13,10 +13,22 @@ func ReportSingleApp(appName string, format string, infoFlag string) error {
}
flags := map[string]common.ReportFunc{
"--network-bind-all-interfaces": reportBindAllInterfaces,
"--network-attach-post-create": reportAttachPostCreate,
"--network-attach-post-deploy": reportAttachPostDeploy,
"--network-web-listeners": reportWebListeners,
"--network-bind-all-interfaces": reportBindAllInterfaces,
"--network-attach-post-create": reportAttachPostCreate,
"--network-attach-post-deploy": reportAttachPostDeploy,
"--network-computed-attach-post-create": reportComputedAttachPostCreate,
"--network-computed-attach-post-deploy": reportComputedAttachPostDeploy,
"--network-computed-bind-all-interfaces": reportComputedBindAllInterfaces,
"--network-computed-initial-network": reportComputedInitialNetwork,
"--network-computed-tld": reportComputedTld,
"--network-global-attach-post-create": reportGlobalAttachPostCreate,
"--network-global-attach-post-deploy": reportGlobalAttachPostDeploy,
"--network-global-bind-all-interfaces": reportGlobalBindAllInterfaces,
"--network-global-initial-network": reportGlobalInitialNetwork,
"--network-global-tld": reportGlobalTld,
"--network-initial-network": reportInitialNetwork,
"--network-tld": reportTld,
"--network-web-listeners": reportWebListeners,
}
flagKeys := []string{}
@@ -30,10 +42,6 @@ func ReportSingleApp(appName string, format string, infoFlag string) error {
return common.ReportSingleApp("network", appName, infoFlag, infoFlags, flagKeys, format, trimPrefix, uppercaseFirstCharacter)
}
func reportBindAllInterfaces(appName string) string {
return common.PropertyGet("network", appName, "bind-all-interfaces")
}
func reportAttachPostCreate(appName string) string {
return common.PropertyGet("network", appName, "attach-post-create")
}
@@ -42,6 +50,83 @@ func reportAttachPostDeploy(appName string) string {
return common.PropertyGet("network", appName, "attach-post-deploy")
}
func reportBindAllInterfaces(appName string) string {
return common.PropertyGet("network", appName, "bind-all-interfaces")
}
func reportComputedAttachPostCreate(appName string) string {
value := reportAttachPostCreate(appName)
if value == "" {
value = reportGlobalAttachPostCreate(appName)
}
return value
}
func reportComputedAttachPostDeploy(appName string) string {
value := reportAttachPostDeploy(appName)
if value == "" {
value = reportGlobalAttachPostDeploy(appName)
}
return value
}
func reportComputedBindAllInterfaces(appName string) string {
value := reportBindAllInterfaces(appName)
if value == "" {
value = reportGlobalBindAllInterfaces(appName)
}
return value
}
func reportComputedInitialNetwork(appName string) string {
value := reportInitialNetwork(appName)
if value == "" {
value = reportGlobalInitialNetwork(appName)
}
return value
}
func reportComputedTld(appName string) string {
value := reportTld(appName)
if value == "" {
value = reportGlobalTld(appName)
}
return value
}
func reportGlobalAttachPostCreate(appName string) string {
return common.PropertyGet("network", "--global", "attach-post-create")
}
func reportGlobalAttachPostDeploy(appName string) string {
return common.PropertyGet("network", "--global", "attach-post-deploy")
}
func reportGlobalBindAllInterfaces(appName string) string {
return common.PropertyGetDefault("network", "--global", "bind-all-interfaces", "false")
}
func reportGlobalInitialNetwork(appName string) string {
return common.PropertyGet("network", "--global", "initial-network")
}
func reportGlobalTld(appName string) string {
return common.PropertyGet("network", "--global", "tld")
}
func reportInitialNetwork(appName string) string {
return common.PropertyGet("network", appName, "initial-network")
}
func reportTld(appName string) string {
return common.PropertyGet("network", appName, "tld")
}
func reportWebListeners(appName string) string {
return strings.Join(GetListeners(appName, "web"), " ")
}

View File

@@ -18,6 +18,15 @@ func main() {
var err error
switch trigger {
case "docker-args-process-build":
appName := flag.Arg(0)
err = network.TriggerDockerArgsProcess(appName)
case "docker-args-process-deploy":
appName := flag.Arg(0)
err = network.TriggerDockerArgsProcess(appName)
case "docker-args-process-run":
appName := flag.Arg(0)
err = network.TriggerDockerArgsProcess(appName)
case "install":
err = network.TriggerInstall()
case "network-build-config":

View File

@@ -2,6 +2,7 @@ package network
import (
"fmt"
"io/ioutil"
"os"
"strings"
"unicode/utf8"
@@ -10,6 +11,22 @@ import (
"github.com/dokku/dokku/plugins/config"
)
// TriggerDockerArgsProcess outputs the network plugin docker options for an app
func TriggerDockerArgsProcess(appName string) error {
stdin, err := ioutil.ReadAll(os.Stdin)
if err != nil {
return err
}
initialNetwork := reportComputedInitialNetwork(appName)
if initialNetwork != "" {
fmt.Printf(" --network=%s ", initialNetwork)
}
fmt.Print(string(stdin))
return nil
}
// TriggerInstall runs the install step for the network plugin
func TriggerInstall() error {
if err := common.PropertySetup("network"); err != nil {
@@ -106,9 +123,20 @@ func TriggerNetworkGetPort(appName string, processType string, containerID strin
// TriggerNetworkGetProperty writes the network property to stdout for a given app container
func TriggerNetworkGetProperty(appName string, property string) error {
defaultValue := GetDefaultValue(property)
value := common.PropertyGetDefault("network", appName, property, defaultValue)
fmt.Println(value)
computedValueMap := map[string]common.ReportFunc{
"attach-post-create": reportComputedAttachPostCreate,
"attach-post-deploy": reportComputedAttachPostDeploy,
"bind-all-interfaces": reportComputedBindAllInterfaces,
"initial-network": reportComputedInitialNetwork,
"tld": reportComputedTld,
}
fn, ok := computedValueMap[property]
if !ok {
return fmt.Errorf("Invalid network property specified: %v", property)
}
fmt.Println(fn(appName))
return nil
}
@@ -190,9 +218,7 @@ func TriggerPostContainerCreate(containerType string, containerID string, appNam
}
property := "attach-post-create"
defaultValue := GetDefaultValue(property)
networkName := common.PropertyGetDefault("network", appName, property, defaultValue)
networkName := reportComputedAttachPostCreate(appName)
if networkName == "" {
return nil
@@ -232,9 +258,7 @@ func TriggerPostDelete(appName string) error {
// TriggerCorePostDeploy associates the container with a specified network
func TriggerCorePostDeploy(appName string) error {
property := "attach-post-deploy"
defaultValue := GetDefaultValue(property)
networkName := common.PropertyGetDefault("network", appName, property, defaultValue)
networkName := reportComputedAttachPostDeploy(appName)
if networkName == "" {
return nil
}

View File

@@ -15,6 +15,7 @@ teardown() {
[[ -f "$DOKKU_ROOT/HOSTNAME.bak" ]] && mv "$DOKKU_ROOT/HOSTNAME.bak" "$DOKKU_ROOT/HOSTNAME" && chown dokku:dokku "$DOKKU_ROOT/HOSTNAME"
docker network rm create-network || true
docker network rm deploy-network || true
docker network rm initial-network || true
global_teardown
}
@@ -162,6 +163,11 @@ teardown() {
echo "status: $status"
assert_success
run /bin/bash -c "dokku network:create initial-network"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku network:set $TEST_APP attach-post-create nonexistent-network"
echo "output: $output"
echo "status: $status"
@@ -193,6 +199,11 @@ teardown() {
echo "status: $status"
assert_success
run /bin/bash -c "dokku network:set $TEST_APP initial-network initial-network"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku ps:rebuild $TEST_APP"
echo "output: $output"
echo "status: $status"
@@ -204,6 +215,11 @@ teardown() {
echo "status: $status"
assert_failure
run /bin/bash -c "dokku --force network:destroy initial-network"
echo "output: $output"
echo "status: $status"
assert_failure
run /bin/bash -c "dokku --force apps:destroy $TEST_APP"
echo "output: $output"
echo "status: $status"
@@ -221,4 +237,9 @@ teardown() {
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku --force network:destroy initial-network"
echo "output: $output"
echo "status: $status"
assert_success
}